Uniswap / web3-react

A simple, maximally extensible, dependency minimized framework for building modern Ethereum dApps
https://web3-react-mu.vercel.app/
GNU General Public License v3.0
5.56k stars 1.52k forks source link

Use two providers at the same time (one Ethereum, other — Polygon) #485

Closed ungarson closed 2 years ago

ungarson commented 2 years ago

I'd like to use two providers at the same time, one is Web3Proivder, which I get through Metamask connection, and it works fine. I'm stuck at setting up provider for Polygon right now. I want to read data from storage from Polygon contracts, how do I do that?

This is the code that works:

function callWithActiveProvider() {
    const { library, account, chainId } = useActiveWeb3React();
    const contract: Contract | null = useMemo(() => getCollectContract(library, account, chainId), [
        library,
        account,
        chainId,
    ]);

    contract.callSomeMethod();
} 

callWithActiveProvider(); // this works

This does not:

function callWithPolygonProvider() {
    const { library, account, chainId } = ???????();
    const contract: Contract | null = useMemo(() => getCollectContract(library, account, chainId), [
        library,
        account,
        chainId,
    ]);

    contract.callPolygonMethod();
}

callWithPolygonProvider() // but how do I do this?

This is the functions/imports that are used above:

import { useWeb3React, useWeb3React as useWeb3ReactCore } from '@web3-react/core';

function getSigner(library: Web3Provider, account: string): JsonRpcSigner {
    return library.getSigner(account).connectUnchecked();
}

function getProviderOrSigner(
    library: Web3Provider,
    account?: string,
): Web3Provider | JsonRpcSigner {
    return account ? getSigner(library, account) : library;
}    

function getContract(
    address: string,
    ABI: any,
    library: Web3Provider,
    account?: string,
): Contract {
    if (!isAddress(address) || address === AddressZero) {
        throw Error(`Invalid 'address' parameter '${address}'.`);
    }

    return new Contract(address, ABI, getProviderOrSigner(library, account) as any);
}

function useActiveWeb3React(): Web3ReactContextInterface<Web3Provider> & {
  chainId?: ChainId;
} {
  const context = useWeb3ReactCore<Web3Provider>();
  const contextNetwork = useWeb3ReactCore<Web3Provider>(NetworkContextName);
  return context.active ? context : contextNetwork;
}

function getCollectContract(library: Web3Provider, account: string, chainId: ChainId) {
    return getContract(CONTRACT_ADDRESS, CONTRACT_ABI, library, account);
}

The hardest part is that both of them should work at the same time, so user can make a transaction on Ethereum, and we should be able to make a request to read storage from Polygon contract in the background.

ghardin1314 commented 2 years ago

Are you using v6 or v8? You can do this with both version but how you do it is different with each

ungarson commented 2 years ago

@ghardin1314

    "@web3-react/core": "^6.1.9",
    "@web3-react/fortmatic-connector": "^6.1.6",
    "@web3-react/injected-connector": "^6.0.7",
    "@web3-react/portis-connector": "^6.1.9",
    "@web3-react/walletconnect-connector": "6.2.4",
    "@web3-react/walletlink-connector": "^6.2.5",
ghardin1314 commented 2 years ago

So with v6 you can use multiple providers. First you wrap our app in 2 providers with different names REF

const Web3ReactProviderPolygon = createWeb3ReactRoot('polygon')

function App () {
  return (
    <Web3ReactProvider getLibrary={getLibrary}>
      <Web3ReactProviderPolygon getLibrary={getLibrary}>
        {/* <...> */}
      </Web3ReactProviderReloaded>
    </Web3ReactProvider>
  )
}
}

Then you can connect an always on network provider using the useWeb3React() hook with the same tag:

function connectNetwork() {
const { activate } =  useWeb3React("polygon");

const network = new NetworkConnector({ urls: { 137: POLYGON-RPC-ENDPOINT } })

activate(network)
}

Then you can use that connector here:

function callWithPolygonProvider() {
    const { library, account, chainId } = useWeb3React("polygon");
    const contract: Contract | null = useMemo(() => getCollectContract(library, account, chainId), [
        library,
        account,
        chainId,
    ]);

    contract.callPolygonMethod();
}

This is a bit sudo codey so it may not work with direct copy paste but should put you on the right track

ungarson commented 2 years ago

@ghardin1314 thank you, it've saved my life! Exactly what I needed 👍🏻

ghardin1314 commented 2 years ago

@NoahZinsmeister I think this can be closed now

bomb-on commented 2 years ago

Are you using v6 or v8? You can do this with both version but how you do it is different with each

Sorry for posting in closed thread, but can you maybe provide this information for v8 as well? Thanks!

mliu commented 1 year ago

+1 to @bomb-on 's request, would love an example for v8 if possible.