ethereumblockchainsmartcontractsmetamaskwallet-connect

window.ethereum.providers.find((provider) => provider.isMetamask) returns undefined


Metamask wallet will not connect if coinbase is installed.

This is a critical issue for anyone trying to execute transactions on their website. Asking users to remove their coinbase wallet is a major deterrent.

https://docs.metamask.io/guide/ethereum-provider.html#using-the-provider

This link on the metamask website demonstrates that they are aware of the issue but no documentation addresses it.

This issue can't be impossible to fix because sites like uniswap allow users to select which wallet. So I think it would be helpful if this was addressed in the documentation.


This is the original code for the connect function:

const connectMetamask = async (setAlert, setCurrentAccount) => {
  const {ethereum} = window
  const isInstalled = () => {
    return Boolean(ethereum && ethereum.isMetaMask)
  }
  const isConnect = () => {
    return Boolean(ethereum && ethereum.isConnected()) // <-- this is the issue
  }
  try {
    if (!isInstalled()) {
      console.log("No metamask!"); // <-- this works
      setAlert(true);
      return;
    }
    if (!isConnect()) {
      console.log("Metamask not connected!");
      setAlert(true)
      return;
    }
    const chainId = await ethereum.request({ method: "eth_chainId" });
  } catch (error) {
    console.error(error);
  }
};

This code works fine to connect metamask IF coinbase wallet is not installed.


https://docs.cloud.coinbase.com/wallet-sdk/docs/injected-provider-guidance This link suggests what to do- but it doesn't work (for me at least).

 if (window.ethereum.providers?.length) {
      window.ethereum.providers.forEach(async (p) => {
        if (p.isMetaMask) provider = p;
      });
    }

window.ethereum.providers returns an array, first element being the coinbase wallet which works fine, second being a proxy containing metamask. The properties of this proxy object are not accessible.


As per some answers I've written (which is the same as the code in the coinbase example):

const metamaskProvider = await window.ethereum.providers.find((provider) => provider.isMetaMask);
ethereum.setSelectedProvider(metamaskProvider)

Logging metamaskProvider returns undefined. Logging window.ethereum.providers returns an array:

0: v {_events: {…}, _eventsCount: 0, _maxListeners: undefined, _filterPolyfill: e.FilterPolyfill, _subscriptionManager: e.SubscriptionManager, …}
1: Proxy {_events: {…}, _eventsCount: 0, _maxListeners: 100, _log: u, _state: {…}, …}

1 is the metamask provider. It contains the following properties:

1: Proxy
         [[Handler]]: Object 
                      deleteProperty: ()=>!0
                      [[Prototype]]: Object

         [[Target]]: l
                     chainId: "0x1"
                     enable: ƒ ()
                     isMetaMask: true
                     ....

metamaskProvider returns undefined. How do I access the isMetaMask property, and set my selectedProvider to metamaskProvider ?


Solution

  • My fix:

    const connectMetamask = async (setAlert, setCurrentAccount) => {
      let { ethereum } = window;
    
        try {
          if (!ethereum) {
            console.log("No metamask!");
            setAlert(true);
            return;
          }
          try{
            if (!ethereum.isConnected()) {
            console.log("Metamask not connected!");
            setAlert(true)
            return;
            }
          } catch (error){
            console.error(error)
            try{
              console.log('providers',window.ethereum.providers);
              console.log('ethVar',ethereum)
              ethereum = await window.ethereum.providers.find(
              (provider) => provider.isMetaMask );
              console.log('ethVarAfterFind', ethereum)
            } catch (error){
              console.error(error)
            }
          }
    
          const chainId = await ethereum.request({ method: "eth_chainId" });
          .....
        } catch (error) {
          console.log('error:')
          console.error(error);
        }
    };
    
    export default connectMetamask;
    

    Basically just :

    ethereum = await window.ethereum.providers.find( (provider) => provider.isMetaMask );
    const chainId = await ethereum.request({ method: "eth_chainId" });
    

    Honestly I'm pretty sure I tried this already and it wasn't working but, it is now ¯\_(ツ)_/¯