1

I'm using wagmi react hooks to create a custom hook that handles token allowance and approvals. it returns an object with the allowances of two tokens for a given pool, and functions to approve each token. the goal is to automatically update the allowance amounts after each token is approved so the frontend can update accordingly. it looks like this:

import {useState, useEffect} from 'react'
import {utils} from "ethers"
import {useAccount,useContract, useSigner, useWaitForTransaction, erc20ABI} from "wagmi"
 


function useAllowance(poolData) {
    const [allowanceData, setAllowanceData] = useState({})
    const [hash, setHash] = useState("")
    const {data: signer} = useSigner();
    const {address} = useAccount();
    const amount = utils.parseEther("10000000");

    const tokenA = useContract({
        addressOrName: poolData.addressA,
        contractInterface: erc20ABI,
        signerOrProvider: signer
    })
    const tokenB = useContract({
        addressOrName: poolData.addressB,
        contractInterface: erc20ABI,
        signerOrProvider: signer
    })

    const getAllowance = async() => {
        let token1Allowance = await tokenA.allowance(address, poolData.address)
        let token2Allowance = await tokenB.allowance(address, poolData.address)

        setAllowanceData({
            tokenA: token1Allowance,
            tokenB: token2Allowance
        })

    } 
    

    
    const {isSuccess,isFetching,isLoading} = useWaitForTransaction({
        hash: hash,
        onSuccess(data, error) {
            getAllowance()
            console.log("error:", error)
            console.log("data:", data)
          },
      })

    
    
    
    const approveA = async () => {
        const results = await tokenA.connect(signer).approve(poolData.address, amount);
        setHash(results.hash)
    }
    const approveB = async () => {
        const results = await tokenB.connect(signer).approve(poolData.address, amount)
        setHash(results.hash)
    }


    useEffect(()=> {
        getAllowance()
        
    },[poolData.address])

  return {allowanceData, approveA, approveB}
}

export default useAllowance

I know that each approve function uses the same hash variable, so if the user calls both functions quickly the first one wont be waited for, I figured since getAllowance gets both allowances this shouldn't be a big deal. I'll probably change it though. also I'm pretty sure this isn't causing my main issue here.

the problem is the allowances aren't updated when getAllowance() is called in the onSuccess function, its as if onSuccess is called too early? if I immediately refresh the page, the allowances are updated. I know that onSuccess is called because "error" is logged and is undefined and "data" is logged and has all the block info like blockHash, blockNumber, ... effectiveGasPrice, ... etc.

Ive also tried this:

useEffect(()=> {
   if(isSuccess) {
      getAllowance()

}


},[isSuccess])

but the same thing happened. I even tried adding a time delay of a few seconds like this:

    useEffect(() => {
      if(isSuccess) {
         const timer = setTimeout(() => getAllowance(), 4000);
         return () => clearTimeout(timer);    
         }
        
       }, [isSuccess]);

this is seems to work for the most part, but not always and is the least elegant way of doing it.

I ALSO tried using more wagmi hooks like this:

    const { config: tokenAConfig } = usePrepareContractWrite({
        addressOrName: poolData.addressA,
        contractInterface: erc20ABI,
        functionName: 'approve',
        args: [poolData.address, amount]
      })

      const { config: tokenBConfig } = usePrepareContractWrite({
        addressOrName: poolData.addressB,
        contractInterface: erc20ABI,
        functionName: 'approve',
        args: [poolData.address, amount]
      })
      const { write: approveA, isSuccess: tokenASuccess } = useContractWrite({
        ...tokenAConfig,
        onSuccess() {
            getAllowance()
        }
    
    })
      const { write: approveB, isSuccess: tokenBSuccess } = useContractWrite({
        ...tokenBConfig,
        onSuccess() {
            getAllowance()
        }
      })

but I get the same issue as far as I can tell.

I'm using foundry, and also tried goerli

for some reason, earlier when I was building this project, this hook was working correctly. I forget how I wrote it then, or maybe it was a fluke or something, but thats why I think theres a small fix I'm missing here.

Anybody know whats going on? or, if you wrote a hook like this, how would you do it?

Thanks!!

1 Answer 1

2

have you tried with

  const results = await tokenA.connect(signer).approve(poolData.address, amount);
  await results.wait()

Hope it helps

1
  • that does work! thank you. Dec 22, 2022 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.