ethers-io / ethers.js

Complete Ethereum library and wallet implementation in JavaScript.
https://ethers.org/
MIT License
7.97k stars 1.85k forks source link

Add WalletConnect Provider #775

Closed fritzschoff closed 4 years ago

fritzschoff commented 4 years ago

I'm supporting MetaMask and WalletConnect in my Angular 9 DApp. And I was asking myself, is there a way for ethers.js to instantiate a provider/signer which fits the need of WalletConnect? You need this npm package: walletconnect And then you can do the following:

this.provider = new WalletConnect({
            bridge: "https://bridge.walletconnect.org",
        });
        // Check if connection is already established
        if (!this.provider.connected) {
            // create new session
            this.provider.createSession().then(() => {
                // get uri for QR Code modal
                const uri = this.provider.uri;
                // display QR Code modal
                WalletConnectQRCodeModal.open(uri, () => {
                    console.log("QR Code Modal closed");
                });
            });

            // Subscribe to connection events
            this.provider.on("connect", (error, payload) => {
                if (error) {
                    throw error;
                }

                // Close QR Code Modal
                WalletConnectQRCodeModal.close();

                // Get provided accounts and chainId
                const { accounts, chainId } = payload.params[0];
            });

            this.provider.on("session_update", (error, payload) => {
                if (error) {
                    throw error;
                }

                // Get updated accounts and chainId
                const { accounts, chainId } = payload.params[0];
            });

            this.provider.on("disconnect", (error, payload) => {
                if (error) {
                    throw error;
                }
                this.web3Store.update({ isConnected: false })
            })
        }

It is a bit annoying to have two "connectors to web3". Would be nice if ethers.js can handle this case. For instance. React has such a wrapper lib that can work with ethers.js and web3.js web3react I guess this is the provider they create depending on the lib you are using(ethers.js, web3.js): WalletConnectProvider I'm not an expert ethers.js so this seems a bit random. But maybe some experienced devs have an idea.

ricmoo commented 4 years ago

I need to look more into Wallet Connect, but this seems like a good idea, adding a WalletConnectSigner. I'll look into it next week. :)

fritzschoff commented 4 years ago

How to instantiate a provider from walletConnect Docs Some results after playing around with this npm lib. Screenshot from 2020-04-02 23-11-22 Screenshot from 2020-04-02 23-11-17

Seems to work, but didn't tested yet

pedrouid commented 4 years ago

I’d love to help with this... I was actually looking into the Provider documentation to actually make the WalletConnect provider based on ethers instead of web3-provider-engine.

Do you think that would be doable? The reason I’ve depended on web3-provider-engine until now is because it was the most stable solution for web3.js but I wonder if you had success with getting compatibility accross libraries

fritzschoff commented 4 years ago

@pedrouid I 'm trying to implement your lib into my dapp. web3modal . It works fine with meta mask, but for wallet it is almost like a new instance, cause functions like getSigner() doesn't exist

pedrouid commented 4 years ago

Have you tried wrapping the @walletconnect/web3-provider with ethers Web3Provider?

Example

import { providers } from "ethers"
import WalletConnectProvider from "@walletconnect/web3-provider"

const provider = new providers.Web3Provider(
  new WalletConnectProvider({
    infuraId: "27e484dcd9e3efcfd25a83a78777cdf1" // Required
  })
)

PS - please use the version 1.0.0-rc.4 for better results

fritzschoff commented 4 years ago

can't somehow make the web3-provider work since the qr-image lib is throwing an error when I want to serve app. Seems an issue about recent releases. @pedrouid As you can see above I already was able to implement the web3provider from ethers with walletconnect.

ricmoo commented 4 years ago

What is the error? Ethers should certainly not be interfering with a QR code library...

fritzschoff commented 4 years ago

It's a wallet connect error, not a ethers error. The qr-image module doesn't have the zlib module exported anymore, didn't investigate in that too much

pedrouid commented 4 years ago

Hey @fritzschoff, there was a report about a weird issue with qrcode-modal from one of the dependencies reported here: https://github.com/WalletConnect/walletconnect-monorepo/issues/299

I've published 1.0.9 on NPM under the next tag. Could you test if this fixed your issue?

fritzschoff commented 4 years ago

Nice work!! Thanks, I will test it

fritzschoff commented 4 years ago
     const walletConnectProvider = new WalletConnectProvider({
        infuraId: infura.id, // Required
        qrcode: true
      });
      await walletConnectProvider.enable();
      this.provider = new providers.Web3Provider(walletConnectProvider)

I'm closing this issue, since it is working like a charm now with the method above. "@walletconnect/web3-provider": "^1.2.0-alpha.0", "ethers": "^5.0.8",

pedrouid commented 4 years ago

Great to hear 🙌 I will go ahead and publish 1.2.0 then

James-Unicrypt commented 4 years ago

any update on how to get a signer with this approach?

fritzschoff commented 4 years ago

provider.getSigner()

EvilJordan commented 4 years ago

My goal is to use ethers (and all my configured keys for that provider's APIs) and the web3modal to connect to walletconnect. To be clear, one needs to import all of the following to get this to work, right:

My confusion is around the web3-provider package and why it's necessary if ethers is the preferred choice/involved.

EvilJordan commented 3 years ago

@fritzschoff Did you get ethers working with web3modal? If so, can you post your code? I've been struggling with this for months.

fritzschoff commented 3 years ago

It has been a while but you should be able to const provider = await web3modal.connect() and this provider variable, you can use with ethers new providers.Web3Providee(provider) . Writing this of the top of my head, so might be a typo here and there. This issue was about wallet connect,no? I had issues with how they bundled their library. If I would used it, I ended up the nodejs modules in the browser which obviously doesn't work. But for that @pedrouid maybe can help you or you check your webpack config, or what ever you are using

dievardump commented 3 years ago

Hello :) I've just opened a discussion https://github.com/ethers-io/ethers.js/discussions/1966 about this.

The solution found in this thread forces users to have an infuraId

However, the standalone client already allows things like eth_sendTransaction, signTransaction etc... so I would like to know if it would be possible to actually have a WalletConnect Provider in ethers.js that uses those and completely saves us from the obligation to have a centralized (infura) dependency?

EvilJordan commented 3 years ago

Super-sad to run into the same problem months later, google, and find myself in the thread 🤪. For some reason, this code does not use the provided infuraId and, instead, uses the built-in ethers-provided id:

const providerOptions = {
        walletconnect: {
            package: window.WalletConnectProvider.default,
            options: {
                infuraId: 'xxx'
            }
        }
    };

 web3Modal = new window.Web3Modal.default({
      cacheProvider: true,
      providerOptions,
      disableInjectedProvider: false
  });

provider = await web3Modal.connect();
const wallet = new ethers.providers.Web3Provider(provider);

This is using: ethers-5.5.1 web3modal@1.9.4 walletconnect/web3-provider@1.6.6

ricmoo commented 3 years ago

This seems like an issue with Web3Modal. Is it passing the infuraId along correctly?

EvilJordan commented 3 years ago

Unclear. The provided key appears in the web3Modal.providerController.providerOptions.walletconnect.options.infuraId object (as expected), but the resulting provider object from the await web3Modal.connect() call doesn't seem to provide any insight into what's going on.

EvilJordan commented 3 years ago

I have apparently solved the issue, somehow as I am not seeing any calls out to infura or any other service in my network tab, but everything is working as expected, and quickly. I hate computers.

Shazambom commented 2 years ago

I've also run into this problem and it doesn't seem like any of the above solutions has helped me.

This is my connection code:

const providerOptions = {
    walletconnect: {
        package: WalletConnectProvider,
        options: {
            infuraId: WALLET_CONNECT_API_KEY,
        }
    }
};
const web3Modal = new Web3Modal({
    network: 'mainnet',
    cacheProvider: false,
    disableInjectedProvider: false,
    providerOptions
});
const provider = await web3Modal.connect();
this.provider = new ethers.providers.Web3Provider(provider, "any");

I see the infuraId in the rpc call to infura. I can get the signer from the provider and even the address of the wallet from the signer. But if I try and perform any blockchain operation like getBalance() or getTransactionCount() I get a ton of 401 HTTP errors from https://mainnet.infura.io with the error from ethers being: PollingBlockTracker - encountered an error while attempting to update latest block: undefined

I get errors when I call functions like this: await this.provider.getSigner().getBalance().then((bal) => {return parseFloat(ethers.utils.formatEther(bal))}));

I wonder what @EvilJordan's solution was...

Dependencies: "web3modal": "^1.9.4" "@walletconnect/web3-provider": "^1.6.6" "ethers": "^5.5.1"

EvilJordan commented 2 years ago

It was that I was double-injecting the provider and using two sets of keys: mine and the default ethers’. 100% user-error (which shouldn’t be a surprise because I am an idiot).

Shazambom commented 2 years ago

I figured it out. I was using the wrong key. I went to infura's website and got a key there and everything worked.

giovanni-caiazzo commented 2 years ago

Hi all, I was trying to follow this for my React Native project. I have ethers installed with @walletconnect/react-native-dapp. The problem is that @walletconnect/react-native-dapp does not expose the provider that @walletconnect/web3-provider exposes and the rpcUrl field of its connector object is empty. I am stumped, because I have no idea on how to use WalletConnect as a signer with ethers and @walletconnect/web3-provider is not compatible with react native projects because it requires some DOM properties

shawnmitchell commented 2 years ago

Hi all, I was trying to follow this for my React Native project. I have ethers installed with @walletconnect/react-native-dapp. The problem is that @walletconnect/react-native-dapp does not expose the provider that @walletconnect/web3-provider exposes and the rpcUrl field of its connector object is empty. I am stumped, because I have no idea on how to use WalletConnect as a signer with ethers and @walletconnect/web3-provider is not compatible with react native projects because it requires some DOM properties

I'm using this from a member of DeveloperDAO. It has a bunch of shims and allows me to create a web3-provider instance.

https://github.com/clxyder/walletconnect-expo-example

giovanni-caiazzo commented 2 years ago

Thanks, I also found a solution which is a bit different. @walletconnect/web3-provider must be used together with @walletconnect/react-native-dapp so that you can set (example for BSC chain):

const provider = new WalletConnectProvider({
        rpc: {
            56: 'https://bsc-dataseed1.binance.org:443',
        },
        chainId: 56,
        connector: connector,
        qrcode: false,
    });

where connector is the instance passed by @walletconnect/react-native-dapp and qrcode: false is needed because otherwise it tries to call window.document.

Also for expo users: unfortunately to get walletconnect working on Android 11+ you need at least to expo prebuild to add

<queries>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="https"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="http"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="wc"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="mqtt"/>
    </intent>
    <intent>
      <action android:name="android.intent.action.VIEW"/>
      <category android:name="android.intent.category.BROWSABLE"/>
      <data android:scheme="wamp"/>
    </intent>
  </queries>

Otherwise your app can't see which apps are installed that support wallet connect and can't also send websocket requests (this last part I am not too sure, but at least you need the wc intent)

shawnmitchell commented 2 years ago
          const walletConnectProvider = new WalletConnectWeb3Provider({
            infuraId: "ca5bfb223**********ced407f803d",
            chainId: 4,
            connector: connector,
            pollingInterval: 8000
          });
          await walletConnectProvider.enable();
          const provider = new providers.Web3Provider(
            walletConnectProvider
          );
          setSigner(provider.getSigner());

this works for me. setSigner() is setting useState state and I can use that signer to request signatures from metamask in iOS and Android. connector is from useWalletConnect() and providers is import { providers } from 'ethers';

intergalacticspacehighway commented 2 years ago

@shawnmitchell @giovanni-caiazzo I tried following what you have done but getting the below error. Have you seen this before?

IMG_441ECAFD003A-1

Musheer-4screen commented 1 year ago

@intergalacticspacehighway I'm facing the same issue. Did you found any solution?

@shawnmitchell @giovanni-caiazzo I tried following what you have done but getting the below error. Have you seen this before?

IMG_441ECAFD003A-1

KarthickSakthi commented 1 year ago

The same case I need toimplement in my Dapp . The above is Complex!!.. I need to implement both Metamask connection and WalletConnect Connection using Ether.js.

Need to implement the Provider for Metamask and WalletConnect Dynamically!. if the user Connected via metamask, ether.js provider will be for Metamask and getSigner() too. if user Connected via WalletConnect means now provider in Ether.js will be WalletConnect! Dynamically.

How Do I achieve this using Ether.js??