web3-react icon indicating copy to clipboard operation
web3-react copied to clipboard

RFC: add useContract hook to core

Open agcty opened this issue 2 years ago • 0 comments

I often come across libraries or codebases that basically reimplement useContract, getContract, etc. originally seen in the Uniswap interface codebase. I've been pondering if it makes sense to officially add this functionality to web3-react.

Usually, I very heavily lean towards separation of concerns and think web3-react's core strength is connecting wallets to dApps, but adding a useContract hook might make sense given that web3-react and some form of useContract are used so often in conjunction with each other.

Here's how this could look like:

import { useMemo } from "react"

import { AddressZero } from "@ethersproject/constants"
import { Provider } from "@ethersproject/providers"
import { useWeb3React } from "@web3-react/core"
import { Contract, ContractInterface, Signer } from "ethers"
import { isAddress } from "ethers/lib/utils"

export function getContract<T = Contract>(
  address: string,
  abi: ContractInterface,
  provider: Signer | Provider
) {
  return <T>(<unknown>new Contract(address, abi, provider))
}

export function useContract<Contract = any>(
  address: string,
  abi: ContractInterface
) {
  const { provider } = useWeb3React()

  const signerOrProvider = useMemo(() => {
    if (provider?.["getSigner"]) {
      return provider.getSigner()
    } else {
      return provider
    }
  }, [provider])

  if (!isAddress(address) || address === AddressZero) {
    throw Error(`Invalid 'address' parameter '${address}'.`)
  }

  const contract = useMemo(
    () => getContract<Contract>(address, abi, signerOrProvider),
    [address, abi, signerOrProvider]
  )

  return contract
}

The implementation is very simple and personally, I think I'd be more comfortable knowing this came from a trusted library that tests the functionality and keeps the logic up-to-date instead of copying it over and over again.

I don't think web3-react should ever be concerned with data-fetching like e.g wagmi or useDapp are because different projects have different needs and imo data fetching should be up to the individual projects. E.g libraries like swr or react-query handle caching, refetchting, deduping etc. quite well already, no need to reinvent the wheel.

However, I do think that providing useContract, getContract and giving examples on how to use them with typechain, on the server (e.g nextjs API routes) and client side, etc. might make sense because 1) it's not really hard to implement/test 2) developers often reimplement this logic anyway.

Everything else that is not part of the "core" library could be a "recipe" in the docs. E.g a useContract + swr data-fetching recipe.

agcty avatar Mar 22 '22 15:03 agcty