use-wallet icon indicating copy to clipboard operation
use-wallet copied to clipboard

How to support multi network handoff

Open supermars01 opened this issue 4 years ago โ€ข 12 comments

How to configure usewalletprovider flexibly? Do you have to pass in fixed chainid and connectors configuration at present?

supermars01 avatar Dec 24 '20 09:12 supermars01

Or how to monitor the 'network changed' event 1610596753(1)

supermars01 avatar Jan 14 '21 03:01 supermars01

You can refer to we3-react/example - useInactiveListener

linxux avatar May 17 '21 17:05 linxux

You can refer to we3-react/example - useInactiveListener

thank you!

supermars01 avatar May 23 '21 11:05 supermars01

How to configure usewalletprovider flexibly? Do you have to pass in fixed chainid and connectors configuration at present?

I created a Context to hold the chainId, passed its value to the chainId prop in UseWalletProvider and updated the context value everytime the network changed

YessineAmor avatar May 29 '21 00:05 YessineAmor

@linxux How is it supposed to be used? I can't find any info on that and I would really appreciate some help!

cosmin-negoita avatar Jul 03 '21 17:07 cosmin-negoita

@linxux How is it supposed to be used? I can't find any info on that and I would really appreciate some help!

  1. For multiple network supported in use-wallet, you can refer to @YessineAmor mentioned.

  2. For switching multiple networks, here are the code snippets.

const useInactiveListener = (suppress: boolean = false) => {
  const { status, error, account } = useWallet()
  const { login } = useAuth()

  useEffect((): any => {
    const { ethereum } = window as any
    if (ethereum && ethereum.on && !suppress) {
      ...
      const handleChainChanged = (chainId: string | number) => {
        console.log("Handling 'chainChanged' event with payload", chainId)
        if (supportedChainId(chainId)) {
          const connetorId = getConnectorId()
          login(connetorId)
        }
      }
      ...
    }
  }
}

const useAuth = (): { login: (connectorId: keyof Connectors | undefined) => void; logout: () => void } => {
  const { error, connect, reset, connector } = useWallet()
  
  useEffect(() => {
    if (!error) return
    if (error instanceof ChainUnsupportedError) {
      const chainId = getTargetChainId() // get the target chainId from Context or any other storages
      
      // call `wallet_addEthereumChain` or `wallet_switchEthereumChain` as you need
      // see [EIP-3085: Wallet Add Ethereum Chain RPC Method (`wallet_addEthereumChain`)](https://eips.ethereum.org/EIPS/eip-3085)
      // and [EIP-3326: wallet_switchEthereumChain](https://ethereum-magicians.org/t/eip-3326-wallet-switchethereumchain/5471)
      chainId && setupChainNetworkByChainId(chainId).then((hasSetup) => {
        if (hasSetup) {
          login(connector)
        }
      })
    }
  }, [error])

  const login = useCallback(async (connectorId: keyof Connectors | undefined) => {
    await connect(connectorId)
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])
  
  const logout = useCallback(() => {
    reset()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])
  
  return { login, logout }
}

linxux avatar Jul 06 '21 08:07 linxux

@linxux Thank you, I think @YessineAmor answer was straight forward, but I couldn't figure out how to retrieve the chainId so I can pass it to the UseWalletProvider. My app will only support ETH and BSC, so I thought I could try to connect to ETH, and if the wallet status returns error, I could retry on BSC. What do you think?

cosmin-negoita avatar Jul 06 '21 10:07 cosmin-negoita

Hi @cosmin-negoita , assume your Dapp has the network switcher for ETH/BSC. when the user chooses the network, then your Dapp could update the chainId in context (ReactContext/Localstorage...). Then you can,

  1. wrapper the UseWalletProvider into your customized provider, and retrieve the chainId from context
  2. or get the the chainId from localstorage after page reload due to the network changed

linxux avatar Jul 06 '21 10:07 linxux

How to configure usewalletprovider flexibly? Do you have to pass in fixed chainid and connectors configuration at present?

I created a Context to hold the chainId, passed its value to the chainId prop in UseWalletProvider and updated the context value everytime the network changed

but how do you determine chainid when you connect with Walletconnect

supermars01 avatar Jul 07 '21 06:07 supermars01

From Metamask docs ( https://docs.metamask.io/guide/ethereum-provider.html#legacy-properties)

If you need to retrieve the current chain ID, use ethereum.request({ method: 'eth_chainId' }) https://docs.metamask.io/guide/ethereum-provider.html#ethereum-request-args. See also the chainChanged https://docs.metamask.io/guide/ethereum-provider.html#chainchanged event for more information about how to handle chain IDs.

The value of this property can change at any time.

On Wed, Jul 7, 2021, 7:23 AM supermars01 @.***> wrote:

How to configure usewalletprovider flexibly? Do you have to pass in fixed chainid and connectors configuration at present?

I created a Context to hold the chainId, passed its value to the chainId prop in UseWalletProvider and updated the context value everytime the network changed

but how do you determine chainid when you connect with Walletconnect

โ€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/aragon/use-wallet/issues/74#issuecomment-875321077, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFAMDDD4UK5OP2RLBSZ3SULTWPXGLANCNFSM4VIAQEUA .

YessineAmor avatar Jul 07 '21 09:07 YessineAmor

//@ts-nocheck
import { useCallback, useEffect, useState } from 'react';

const useChainId = () => {
  const [chainId, setChainId] = useState(97);

  const fetchChainId = useCallback(async () => {
    if (window.ethereum) {
      const ethereum = window.ethereum;
      let chainId = await ethereum.request({
        method: 'eth_chainId',
      });
      chainId = parseInt(chainId, 16);
      setChainId(chainId);

      window.ethereum.on('networkChanged', function (chainId) {
        chainId = parseInt(chainId, 16);
        setChainId(chainId);
      });
    }
  }, []);

  useEffect(() => {
    fetchChainId().catch((err) => console.error(err.stack));

    const refreshChainId = setInterval(fetchChainId, 1000);
    return () => clearInterval(refreshChainId);
  }, []);

  return chainId;
};

export default useChainId;

const UseWalletProviderWrapper = (props) => {
  const chainId = useChainId();
  console.log("๐Ÿš€ ~ file: App.tsx ~ line 35 ~ UseWalletProviderWrapper ~ chainId", chainId)

  return <UseWalletProvider chainId={chainId} {...props}></UseWalletProvider>;
}

ladyruo avatar Nov 17 '21 18:11 ladyruo

@ladyruo thanks a lot for that, had to slightly modify it to fix a memory leak in the interval though

import { useCallback, useEffect, useState } from "react";

const useChainId = () => {
  const [chainId, setChainId] = useState(97);

  const fetchChainId = useCallback(async () => {
    if (window.ethereum) {
      const ethereum = window.ethereum;
      let chainId = await ethereum.request({
        method: "eth_chainId",
      });
      chainId = parseInt(chainId, 16);
      console.log("network changed");
      setChainId(chainId);
    }
  }, [setChainId]);

  useEffect(() => {
    fetchChainId().catch((err) => console.error(err.stack));\

    window.ethereum.on("networkChanged", fetchChainId);
    return () => window.ethereum.removeListener("networkChanged", fetchChainId);
  }, [fetchChainId]);

  return chainId;
};

export default useChainId;
const UseWalletProviderWrapper = (props) => {
  const chainId = useChainId();
  console.log("๐Ÿš€ ~ file: App.tsx ~ line 35 ~ UseWalletProviderWrapper ~ chainId", chainId)

  return <UseWalletProvider chainId={chainId} {...props}></UseWalletProvider>;
}

BitWonka avatar Jun 20 '22 03:06 BitWonka