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

Both Coinbase Wallet and MetaMask triggered on MetaMask icon click #316

Closed
4skinSkywalker opened this issue Aug 26, 2021 · 13 comments
Closed

Comments

@4skinSkywalker
Copy link

Hi, both the Coinbase Wallet and MetaMask are triggered when clicking on MetaMask icon.

image

@Soletiq
Copy link

Soletiq commented Sep 30, 2021

+1 - Web3Modal gets confused when both the Coinbase and Metamask extensions are enabled at the same time. In fact, when I connect to the injected provider, it randomly chooses from one or the other.

Perhaps instead of having a one Injected slot, we need the option to specify which injected providers we want to use.

@gregegan
Copy link

gregegan commented Oct 3, 2021

Yeah this is a pain, happy to have found others are experiencing this issue. I haven't been able to find a consistent pattern of when it shows CB Wallet as an option or not.

@4skinSkywalker
Copy link
Author

4skinSkywalker commented Oct 4, 2021

Hi @Soletiq and @gregegan ,

you can work around this by defining custom options and filter the provider that you want to use.
There are properties inside each providers that give you some info, for instance:

image

I currently have Coinbase and MetaMask providers injected, and I see that only one of them has "isMetaMask" set to true (obviously MetaMask), the other one has "isWalletLink" set to true (and this is Coinbase):

image

Below you can see how I'm able to distinguish between providers, or better to capture the right one on web3modal.connect():

"custom-metamask": {
    display: {
      logo: "assets/img/metamask-logo.svg",
      name: "MetaMask Wallet",
      description: "Connect to your MetaMask Wallet"
    },
    package: true,
    connector: async () => {
        if (!isMetaMaskInstalled()) {
            win.location = "https://metamask.app.link/dapp/www.ethbox.org/app/";
            return;
        }

        let provider = null;
        if (typeof win.ethereum !== 'undefined') {
            let providers = win.ethereum.providers;
            provider = providers.find(p => p.isMetaMask); // <-- LOOK HERE
            try {
                await provider.request({ method: 'eth_requestAccounts' });
            } catch (error) {
                throw new Error("User Rejected");
            }
        } else {
            throw new Error("No MetaMask Wallet found");
        }
        console.log("MetaMask provider", provider);
        return provider;
    }
}

Post Scriptum

I know it's a pain in the ass to handle all wallets as custom options but you have A LOT more flexibility by doing that.

1) You can define whether or not to show some possibilities, for instance Binance Wallet is available only on desktop so you want it only there by default:

// Put here providers that work on every device
let providerOptions = {
    ...MetaMaskOpts, // This is called spread operator, for more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
    ...WalletConnectOpts,
    ...CoinbaseWalletOpts
};

// Put here providers that only works on desktop
if (deviceType() === "desktop") {
    Object.assign(providerOptions, BinanceChainWalletOpts);
}

this.web3Modal = new this.Web3Modal({
    cacheProvider: deviceType() === "desktop",

    providerOptions, // Passing only those providers that I need

    disableInjectedProvider: true
});

2) You can implement custom logic on web3modal.connect(), below I'm deep-linking so that when MetaMask is not injected in the browser (for example on mobile) it redirects to the MetaMask app (or the device app store instead):

"custom-metamask": {
    display: {
      logo: "assets/img/metamask-logo.svg",
      name: "MetaMask Wallet",
      description: "Connect to your MetaMask Wallet"
    },
    package: true,
    connector: async () => {
        if (!isMetaMaskInstalled()) {
            win.location = "https://metamask.app.link/dapp/www.ethbox.org/app/"; // <-- LOOK HERE
            return;
        }

        let provider = null;
        if (typeof win.ethereum !== 'undefined') {
            let providers = win.ethereum.providers;
            provider = providers.find(p => p.isMetaMask);
            try {
                await provider.request({ method: 'eth_requestAccounts' });
            } catch (error) {
                throw new Error("User Rejected");
            }
        } else {
            throw new Error("No MetaMask Wallet found");
        }
        console.log("MetaMask provider", provider);
        return provider;
    }
}

3) Implement providers that are not exactly 100% compliant with the way web3 does its stuff. Below I've implemented a support for Polkadot{.js} wallet using @reef-finance/evm-provider, @polkadot/api, @polkadot/extension-dapp and ethers:

"custom-reefmainnet": {
    display: {
      logo: "assets/img/reef.png",
      name: "Polkadot Wallet",
      description: "Reef Finance Mainnet"
    },
    package: false,
    connector: async () => {

        let WS_URL = "wss://rpc.reefscan.com/ws";

        // Return an array of all the injected sources
        // (this needs to be called first)
        const allInjected = await web3Enable('ethbox dapp');
        console.log("All injected", allInjected);

        let signer;
        if (allInjected[0] && allInjected[0].signer) {
            signer = allInjected[0].signer;
        }

        // Return an array of { address, meta: { name, source } }
        // (meta.source contains the name of the extension)
        const allAccounts = await web3Accounts();
        console.log("All accounts", allAccounts);

        if (allAccounts[0] && allAccounts[0].address) {
            this.selectedAccount$.next(allAccounts[0].address);
        }

        if (!this.selectedAccount$.getValue()) {
            this.loadingIndicatorServ.off();
            return;
        }

        this.provider = new Provider({
            provider: new WsProvider(WS_URL)
        });
        console.log("Provider", this.provider); // <-- LOOK HERE, this is an ethers provider

        await this.provider.api.isReady;

        this.signer = new Signer(
            this.provider,
            this.selectedAccount$.getValue(),
            signer
        );
        console.log("Signer", this.signer); // <-- LOOK HERE, this is an ethers signer
    }
}

@parisan8
Copy link

I need to connect my Coinbase to Metamask which needs RPC URL and chain ID , i cant find it. Can you please help me with that . I'd appreciate it.

@DevSmith0213
Copy link

I need to add to web3 modal now. How can I implement it? Can you please help me with that.
I'd really appreciate it. Thanks.
const providerOptions = { walletconnect: { package: WalletConnectProvider, options: { infuraId: process.env.REACT_APP_INFURA_ID } }, walletLink: { package: WalletLink, // required // options: { // infuraId: process.env.REACT_APP_INFURA_ID // required // } }, portis: { package: Portis, options: { id: process.env.REACT_APP_PORTIS_ID } }, fortmatic: { package: Fortmatic, options: { key: process.env.REACT_APP_FORTMATIC_KEY } }, mewconnect: { package: MewConnect, // required options: { infuraId: process.env.REACT_APP_INFURA_ID // required } }, torus: { package: Torus } };

@kyokosdream
Copy link

@parisan8 and @DevSmith0213 please do not make comments that are completely unrelated to this issue. Github issues are not for whining and asking for general help. You are detracting from the great work done by @4skinSkywalker. If you have a specific issue, open a new issue and share detailed logs of the errors you are experiencing so that the community can better help you.

@parisan8
Copy link

parisan8 commented Apr 20, 2022 via email

@parisan8
Copy link

what is it about you are attacking me here ?!?
Are you trying to make it here uncomfortable for me?
Are you trying to embarrass me? I dont even remember what was my question or where, but you leave a comment to intimidate me ! I take this personally and a big hate speech towards me . If i asked a question and i needed help why you hate me ? @kyokosdream

@audieleon
Copy link

audieleon commented Apr 28, 2022

I want this solution to work, but has anyone tried it? There's an unexplained function call, window appears to be aliased to win, and most importantly, when I fix all that, it still doesn't work. If there is only one provider (window.ethereum) then the providers list is undefined. And even if I try to control for only using MetaMask, Coinbase jumps the gun.

I'm having this issue in Vanilla JavaScript, and from what I gather, web3modal's Coinbase simply doesn't work in vanilla JavaScript (Coinbase's fault, since they only have framework SDKs). However, Coinbase does get in my way EVEN IF I DON'T WANT OR TRY TO IMPLEMENT IT in web3modal.

I think this issue was closed too quickly. Writing custom provider options for injected wallets should not satisfy as a solution. Could we reopen it and see about a real solution? Or if not a real solution, could we get good working guidance? Perhaps with an example implementation that shows the guidance works?

My attempt at making the custom suggestion work is below. Pretty sure the Coinbase provider falls through all my checks, because

        const providerOptions = {
            "custom-Metamask": {
                display: {
                    logo: "https://duckduckgo.com/i/b08b6e4c.png",
                    name: "MetaMask Wallet",
                    description: "Connect to your MetaMask Wallet"
                },
                package: true,
                connector: async () => {
                    let localProvider = null;
                    if (typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask) {
                        console.log(window.ethereum);
                        localProvider = window.ethereum;
                    } else if (window.ethereum.providers !== undefined) {
                        console.log(window.ethereum.providers);
                        let providers = window.ethereum.providers;
                        localProvider = providers.find(p => p.isMetaMask);
                        if (localProvider == undefined) { throw new Error("No MetaMask Wallet found"); }
                    } else {
                        throw new Error("No MetaMask Wallet found");
                    }
                    try {
                        await localProvider.request({ method: 'eth_requestAccounts' });
                    } catch (error) {
                        throw new Error("User Rejected");
                    }
                    console.log("MetaMask provider", localProvider);
                    return localProvider;
                }
            },
            walletconnect: {
                package: WalletConnectProvider,
                options: {
                    infuraId: atob(code),
                }
            },
        };

With the above implementation, Coinbase very definitely connects, and so does metamask (ish). The account information comes from Coinbase wallet.

Looking at the console, I get this condition:
image

Pretty sure this is something worth digging out. How can I help?

@kyokosdream
Copy link

kyokosdream commented Apr 28, 2022

@audieleon Here is my solution which works fine for our React app. I don't know about your vanilla JS implementation.

export const providerOptions = {
  "custom-metamask": {
    display: {
      name: "MetaMask",
      description: "Connect to your MetaMask Wallet",
      logo: process.env.PUBLIC_URL + "/metamask.svg",
    },
    package: true,
    connector: async () => {
      // Case 1: There is no injected provider available
      // Resolution: Open MetaMask download in new tab
      if (window.ethereum == undefined) {
        //console.log("No Injected Providers Available");
        window.open(
          "https://metamask.app.link/dapp/www.ethbox.org/app/",
          "_blank"
        );
        return;
      }
      // Case 2: There are multiple providers available.
      // Resolution: Check if an injected provider is Metamask,
      //  if true, return the provider. If false, open MetaMask download
      //  in new tab.
      else if (window.ethereum.providers !== undefined) {
        let providers = window.ethereum.providers;
        let provider = providers.find((p) => p.isMetaMask); // <-- LOOK HERE
        if (provider) {
          //console.log("MetaMask provider located");
          try {
            await provider.request({ method: "eth_requestAccounts" });
            return provider;
          } catch (error) {
            throw new Error("User Rejected");
          }
        } else {
          //console.log("MetaMask not an available provider");
          window.open(
            "https://metamask.app.link/dapp/www.ethbox.org/app/",
            "_blank"
          );
          return;
        }
      }
      // Case 3: There is one injected provider available.
      // Resolution: If it is MetaMask, return the provider.
      //  Otherwise, open download in new tab.
      else if (
        window.ethereum.providers == undefined &&
        window.ethereum.isMetaMask == true
      ) {
        //console.log("MetaMask is the single injected provider");
        let provider = window.ethereum;
        try {
          await provider.request({ method: "eth_requestAccounts" });
          return provider;
        } catch (error) {
          throw new Error("User Rejected");
        }
      } else {
        window.open(
          "https://metamask.app.link/dapp/www.ethbox.org/app/",
          "_blank"
        );
        return;
      }
    },
  },
  "custom-walletconnect": {
    display: {
      name: "WalletConnect",
      description: "Scan with WalletConnect to connect",
      logo: process.env.PUBLIC_URL + "/walletconnect-circle.svg",
    },
    package: true,
    connector: async () => {
      //  Create WalletConnect Provider
      const provider = new WalletConnectProvider({
        rpc: {
          YOUR-RPC-MAPPING
        },
      });
      //  Enable session (triggers QR Code modal)
      await provider.enable();
      return provider;
    },
  },
  walletlink: {
    package: CoinbaseWalletSDK,
    options: {
      appName: "Candy Chain",
      appLogoUrl:
        "https://res.cloudinary.com/candy-labs/image/upload/v1650650639/candychain-logo_ucdmlg.png",
      infuraId: "YOUR-INFURA-ID",
    },
  },
};

@audieleon
Copy link

audieleon commented Apr 29, 2022

@kyokosdream I used the settings as given above in my vanilla JavaScript solution, and it continues to open Coinbase wallet when I click on Metamask. If both are installed, it doesn't seem to differentiate. Coinbase, as far as I can tell, just does not support vanilla JavaScript.

I believe the problem is in the second condition, where the provider for Metamask just isn't in the providers list at all. The only thing that resolves to Metamask for me is window.ethereum, and the providers list has Coinbase in it. I'm pretty sure some of this is browser specific.

The above is why I think the solution is systematic testing of an implementation that hides this complexity from the users of Web3Modal, and that provably works across all browsers. People with both Coinbase and JavaScript wallets will increase, and this will become unwieldy quickly.

@chadyj chadyj added the v1 label Sep 19, 2022
@parisan8
Copy link

parisan8 commented Dec 7, 2022 via email

@xzilja
Copy link
Contributor

xzilja commented Jan 21, 2023

With stable version 2.0.0 of Web3Modal now released, we are officially dropping support for version 1.x
Due to this this issue/pr was marked for closing. It is highly recommended to upgrade as 2.x will be receiving further updates that will enable functionality for some of our newer sdks like auth and push as well as support for WalletConnect v2 (See this post about WalletConnect v1 being deprecated https://medium.com/walletconnect/walletconnect-v1-0-sunset-notice-and-migration-schedule-8af9d3720d2e)

If you need to continue using Web3Modal 1.x and require this feature/fix implemented, we suggest adding it via forking V1 branch.

@xzilja xzilja closed this as completed Jan 21, 2023
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

11 participants