WalletConnect / web3modal

A single Web3 provider solution for all Wallets
https://web3modal.com
Apache License 2.0
4.69k stars 1.3k forks source link

Will it be possible to access `ethers.providers.Web3Provider` of the connected wallet ? (V2) #602

Closed paouvrard closed 1 year ago

paouvrard commented 1 year ago

We use other libraries which work with ethers.providers.Web3Provider and not ethers.providers.JsonRpcSigner of useSigner()

It would be great if the Web3Provider of the connected wallet can be exposed.

Similar to the useProvider() hook in web3-react.

xzilja commented 1 year ago

Yep, working on this. Should be available as a hook in next release that will go up either today or on Monday.

xzilja commented 1 year ago

useProvider and useWebsocketProvider were added in alpha.5 https://github.com/WalletConnect/web3modal/tree/V2/packages/react#useprovider-example https://github.com/WalletConnect/web3modal/tree/V2/packages/react#usewebsocketprovider-example

Make sure to look over readme as there are some changes in implementation

paouvrard commented 1 year ago

Thank you @IljaDaderko . Is there a way to use ethers.providers.Web3Provider though ? (https://docs.ethers.io/v5/api/providers/other/#Web3Provider) or only ethers.providers.JsonRpcSigner is available from useSigner() for signing a tx ? useProvider is returning ethers.providers.BaseProvider & { chains?: Chain[] }

xzilja commented 1 year ago

@paouvrard I see, I will explore useWeb3Provider hook for next alpha, either by collaborating with guys from wagmi or we'll expose it as custom one 👍

paouvrard commented 1 year ago

@IljaDaderko I noticed that using

const { data } = useSigner()
const provider = data.provider

the data is JsonRpcSigner (not ethers.Signer) so the provider it contains is ethers.providers.Web3Provider even though it is typed as ethers.providers.Provider. So I could use this provider but trying with await provider.getNetwork() gives this error:

Error: underlying network changed (event="changed", network={"name":"unspecified","chainId":0,"ensAddress":null,"_defaultProvider":null}, detectedNetwork={"name":"goerli","chainId":5,"ensAddress":"0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"}, code=NETWORK_ERROR, version=providers/5.6.8)
xzilja commented 1 year ago

Try passing useSigner({chainId: 5}) maybe. I made some changes locally where it is no longer needed, so shouldn't be an issue in next alpha.

paouvrard commented 1 year ago

Got it, yea that worked, but the dApp is handling multiple chains so the same signer is used after switchNetwork. I'll wait for the next alpha. Not sure if it's expected, but the signer data (const { data, refetch } = useSigner()) only becomes available after refetch is called on load.

xzilja commented 1 year ago

@paouvrard Could you try alpha.6. Updated wagmi dependency and useSigner no longer requires { chainId: 5 }, I tested this use case await provider.getNetwork() and got expected result.

As for const { data, refetch } = useSigner() issue with data being available only after refetch, I haven't ran into this issue. data will be undefined initially while it is being fetched, but will resolve to signer eventually. You could add isLoading and error to return of this hook and wait until everything gets resolved before accessing data.

paouvrard commented 1 year ago

Thanks @IljaDaderko It worked with alpha.6. However after doing switchNetwork({ chainId: another_chain }) and then calling await provider.getNetwork()again, I got the same network error as above. The error was resolved by calling refetch() after the network was switched. I don't know if it is the correct way to do it but it's working.

You could add isLoading and error to return of this hook and wait until everything gets resolved before accessing data.

The data is initially undefined as expected and then null until refetch() is called, and then JsonRpcSigner.

xzilja commented 1 year ago

@paouvrard ah I see what you mean, just replicated this. I think it's basically difference in web3modal and wagmi (we use undefined for initial values, they use null) hence you see those diff values. But you still don't need to call re-fetch, you could just use something like

  const onGetNetwork = useCallback(async () => {
    const network = await data?.provider?.getNetwork()
    console.log('network', network)
  }, [data])

  useEffect(() => {
    if (data) onGetNetwork()
  }, [data])

But I'll add a check for null value in next alpha, to ensure it only renders 2 times (undefined -> fetchedData). I think once it sets it to null, we also set isLoading to false incorrectly

paouvrard commented 1 year ago

@IljaDaderko In my case, data will always remain null unless refetch() is called. Looks similar to this issue: https://github.com/WalletConnect/web3modal/issues/604

paouvrard commented 1 year ago

@IljaDaderko There is a similar issue with useSigner when connecting a wallet for the 1st time, the data remains undefined and isLoading is always true before and after the wallet is connected. const { data, isLoading, error, refetch } = useSigner() After switching accounts in MetaMask or reloading the page (with refetch) the data will become JsonRpcSigner and isLoading remains true. Calling refetch after a wallet is newly connected didn't get the data. I'd expect the new signer data to become available right after the wallet is connected.

xzilja commented 1 year ago

Hey @paouvrard so first things first, latest beta should solve the issue with null we discussed before. As for refetch related one, I'm unable to replicate it. Here is a usage example for useSigner

https://github.com/WalletConnect/web3modal/blob/V2/examples/react/src/sections/UseSigner.tsx

That's used in online example https://web3modal.pages.dev/

Is there anything you can see about example implementation that is different from how you are doing things that I could try to replicate?

paouvrard commented 1 year ago

Thank you @IljaDaderko, null is resolved.

I think the difference comes from using useSigner inside a react context provider. I've added this check in several components:

const { data, isLoading, error } = useSigner()
useEffect(() => {
  console.log(data, isLoading, error)
}, [data, isLoading, error])

This is the app structure.

export default function App() {
  return (
    <>
      <ContextProvider1>
        <ContextProvider2>
           {...}
        </ContextProvider2>
      </ContextProvider1>
      <Web3Modal config={modalConfig} />
    </>
  )
}

When used from ContextProvider1: data loaded correctly but isLoading remains true. When used from ContextProvider2 the data remains undefined as described above.

xzilja commented 1 year ago

@paouvrard found the issue with loading never updating, will be fixed in next alpha.

paouvrard commented 1 year ago

Hi @IljaDaderko, checking in regarding the signer issues. I’m continuing to investigate the network switching with beta.3 and running the example locally, but wasn’t able to reproduce fully. We are on React 17.0.2 and Next 12.1.0, is there a min version for web3Modal ? In the example I did confirm that after switching network, the signer is not updated unless refetch is called after the network changed. Using the signer after a network change throws this error:

Error: underlying network changed (event="changed", network={"name":"matic","chainId":137,"ensAddress":null}, detectedNetwork={"chainId":1313161555,"name":"unknown"}, code=NETWORK_ERROR, version=providers/5.7.2)
xzilja commented 1 year ago

Hey @paouvrard starting with next beta.4, we will be dropping our own hooks / controlellrs in favour of allowing users to use https://wagmi.sh directly.

I believe your issue was raised by some bugs in web3modal hooks, so hopefully once you switch to wagmi it will be resolved. Keep your eyes out for next beta release and documentation change. This approach should bring way more stability 👍

paouvrard commented 1 year ago

Thank you @IljaDaderko all above issues are resolved with Beta.5 👍

kwebster2 commented 1 year ago

Hi @paouvrard , so you were able to resolve this?

I am having the same issue with beta.8. I know it's kind of a wagmi issue now, though I imagine it is related to the connector as well.

Anyway, I am getting the same issue - data is always null, unless I call refetch, in which case eventually I'll get the correct JsonRpcSigner object

paouvrard commented 1 year ago

Hi @kwebster2 yea the issue was resolved in Beta.5, I tested again with Beta.9 and that's working well. Make sure to fix the dependency versions like here (I had similar issues with wagmi on the wrong version).