UNPKG

biuauthui

Version:
125 lines (113 loc) 4.25 kB
/* eslint-disable consistent-return */ /* eslint-disable @typescript-eslint/ban-ts-comment */ /* eslint-disable no-console */ /* eslint-disable camelcase */ import { MaxUint256 } from "@ethersproject/constants"; import { AddressZero } from "@ethersproject/constants/src.ts/addresses"; import { TransactionResponse } from "@ethersproject/providers"; import BigNumber from "bignumber.js"; import { useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { useAccount, usePublicClient, useWaitForTransaction, useWalletClient } from "wagmi"; import { Erc20__factory } from "../payTypes/Erc20__factory"; import { useERC20 } from "./useContract"; import useNotification from "./useNotification"; import useTokenAllowance from "./useTokenAllowance"; export enum ApprovalState { UNKNOWN, NOT_APPROVED, PENDING, APPROVED, } export function useApproveCallback( amount: BigNumber | null, tokenAddress: string, spender?: string ): [ApprovalState, () => Promise<TransactionResponse | undefined>, boolean, boolean] { const { address } = useAccount(); const { t } = useTranslation(); const [approveHash, setApproveHash] = useState(""); const [approveLoading, setApproveLoading] = useState(false); const { failedTip, successTip } = useNotification(); const { data: walletClient } = useWalletClient(); const publicClient = usePublicClient(); const { isLoading } = useWaitForTransaction({ hash: approveHash as `0x${string}`, onSuccess() { if (approveHash) { successTip("Approve Success!"); setApproveHash(""); setApproveLoading(false); } }, onError() { if (approveHash) { failedTip("Approve Failed!"); setApproveHash(""); setApproveLoading(false); } }, }); const currentAllowance = useTokenAllowance({ amount, address: tokenAddress }, address ?? undefined, spender, approveHash); // check the current approval status const approvalState: ApprovalState = useMemo(() => { if (!spender) return ApprovalState.UNKNOWN; if (tokenAddress === AddressZero) return ApprovalState.APPROVED; if (!currentAllowance) return ApprovalState.UNKNOWN; return currentAllowance?.isLessThan(amount || new BigNumber(0)) ? ApprovalState.NOT_APPROVED : ApprovalState.APPROVED; }, [amount, tokenAddress, currentAllowance, spender, address, approveHash]); const tokenContract = useERC20(tokenAddress); const approve = useCallback(async (): Promise<any> => { setApproveLoading(true); if (approvalState !== ApprovalState.NOT_APPROVED) { failedTip(t("Approve was called unnecessarily")); console.error("approve was called unnecessarily"); setApproveLoading(false); return undefined; } if (!tokenAddress) { failedTip(t("No token")); console.error("no token"); setApproveLoading(false); return undefined; } if (!tokenContract) { failedTip(t("Cannot find contract of the token %tokenAddress%", { tokenAddress })); console.error("tokenContract is null"); setApproveLoading(false); return undefined; } if (!amount) { failedTip(t("Missing amount to approve")); console.error("missing amount to approve"); setApproveLoading(false); return undefined; } if (!spender) { failedTip(t("No spender")); console.error("no spender"); setApproveLoading(false); return undefined; } const useExact = false; try { const { request } = await publicClient.simulateContract({ abi: Erc20__factory.abi, account: address as `0x${string}`, address: tokenContract.address as `0x${string}`, functionName: "approve", args: [spender, useExact ? amount.toString() : MaxUint256], }); // @ts-ignore const hash = await walletClient?.writeContract(request); if (hash) { setApproveHash(hash); return hash; } setApproveLoading(false); } catch (error) { setApproveLoading(false); } }, [approvalState, tokenAddress, tokenContract, amount, spender, publicClient, walletClient]); return [approvalState, approve, approveLoading, isLoading]; }