From 257614df3500491a3300ae616533635e240f04eb Mon Sep 17 00:00:00 2001 From: torof Date: Mon, 7 Oct 2024 14:23:09 +0200 Subject: [PATCH] fix(deploy fix try): fixing deployment issues 4 --- .../src/components/ui/AllowanceTxButton.tsx | 273 +++++++++--------- 1 file changed, 129 insertions(+), 144 deletions(-) diff --git a/frontend/src/components/ui/AllowanceTxButton.tsx b/frontend/src/components/ui/AllowanceTxButton.tsx index d19802bc..6e401d50 100644 --- a/frontend/src/components/ui/AllowanceTxButton.tsx +++ b/frontend/src/components/ui/AllowanceTxButton.tsx @@ -1,152 +1,137 @@ -import { FC } from "react"; +"use client"; +import { type FC, useEffect, type ReactNode, useState } from "react"; +import { + useSimulateContract, + useReadContract, + useAccount, + UseSimulateContractReturnType, +} from "wagmi"; +import { erc20Abi, zeroAddress } from "viem"; +import { TxButton } from "./TxButton"; +import { Amount } from "./Amount"; +import { twMerge } from "tailwind-merge"; -import { CarouselItem } from "@/components/ui/Carousel"; -import { TxButton } from "@/components/ui"; -import { formatUnits } from "viem"; -import { useSimulateLdyStakingGetReward, useSimulateLdyStakingUnstake } from "@/generated"; -import dayjs from "dayjs"; -import localizedFormat from "dayjs/plugin/localizedFormat"; -import relativeTime from "dayjs/plugin/relativeTime"; -import utc from "dayjs/plugin/utc"; -import { OneMonth, StakeDurations } from "@/constants/staking"; -import { getAPRCalculation } from "@/lib/getAPRCalculation"; -import { QueryKey } from "@tanstack/react-query"; -import { IUserStakingInfo } from "@/services/graph/hooks/useStakingEvent"; -import { getTimeLeftString } from "@/lib/utils"; -import { UseSimulateContractReturnType } from "wagmi"; +interface Props extends React.ComponentPropsWithoutRef { + token: `0x${string}`; + spender: `0x${string}`; + amount?: bigint; + preparation: UseSimulateContractReturnType; + transactionSummary?: string | ReactNode; + // This prevents displaying errors when user hasn't interacted with the button or input yet + hasUserInteracted?: boolean; -dayjs.extend(localizedFormat); -dayjs.extend(relativeTime); -dayjs.extend(utc); + // Allow parent to force error state + parentIsError?: boolean; + parentError?: string; -export interface IPoolInfo { - stakedAmount: bigint; - unStakeAt: bigint; - duration: bigint; - rewardPerTokenPaid: bigint; - rewards: bigint; + // Allow 0 amount + allowZeroAmount?: boolean; } - -export const AppStakingPoolPane: FC<{ - poolInfo: IPoolInfo; - poolIndex: number; - ldyTokenDecimals: number; - userStakingInfo: IUserStakingInfo | undefined; - rewardsArray: readonly bigint[] | undefined; - rewardRate: number; - totalWeightedStake: number; - getUserStakesQuery?: QueryKey; - ldyTokenBalanceQuery?: QueryKey; - rewardsArrayQuery?: QueryKey; -}> = ({ - poolInfo, - poolIndex, - ldyTokenDecimals, - userStakingInfo, - rewardsArray, - rewardRate, - totalWeightedStake, - getUserStakesQuery, - ldyTokenBalanceQuery, - rewardsArrayQuery, +/** + * A version of the TxButton that allows to ensure and set (if needed) a given ERC20 allowance before + * signing the transaction. + */ +export const AllowanceTxButton: FC = ({ + token, + spender, + amount = 0n, + preparation, + transactionSummary = "", + hasUserInteracted = false, + parentIsError = false, + parentError = undefined, + allowZeroAmount = false, + disabled, + className, ...props }) => { + const account = useAccount(); + const [hasEnoughAllowance, setHasEnoughAllowance] = useState(false); + const { data: symbol } = useReadContract({ + abi: erc20Abi, + functionName: "symbol", + address: token, + }); + const { data: decimals } = useReadContract({ + abi: erc20Abi, + functionName: "decimals", + address: token, + }); + const { data: allowance, queryKey: allowanceQueryKey } = useReadContract({ + abi: erc20Abi, + functionName: "allowance", + address: token, + args: [account.address || zeroAddress, spender], + }); + const { data: balance, queryKey: balanceQueryKey } = useReadContract({ + abi: erc20Abi, + functionName: "balanceOf", + address: token, + args: [account.address || zeroAddress], + }); + const allowancePreparation = useSimulateContract({ + abi: erc20Abi, + functionName: "approve", + address: token, + args: [spender, amount], + }); + + // Set hasEnoughAllowance when allowance or amount chanages + useEffect(() => { + preparation.refetch(); + setHasEnoughAllowance(allowance !== undefined && allowance >= amount); + }, [allowance, amount]); + + // Check if the user has enough balance, and raise error else + let isError = false; + let errorMessage: string = ""; + + useEffect(() => { + if (!balance || balance < amount) { + isError = true; + errorMessage = "Insufficient balance"; + } + }, [balance, amount]); + return ( - -
-
- Pool #{poolIndex + 1} -
- Staked Amount - - {formatUnits(poolInfo.stakedAmount, ldyTokenDecimals!)} - -
-
- Duration - {Number(poolInfo.duration) / OneMonth} Months -
-
- Unlock Timestamp - - {dayjs.utc(Number(poolInfo.unStakeAt) * 1000).format("DD/MM/YYYY")} - -
-
- Earned - - {userStakingInfo - ? Number( - formatUnits(BigInt(userStakingInfo.earnedAmount), ldyTokenDecimals!), - ).toFixed(4) - : 0}{" "} - Token - -
-
- APY - - {getAPRCalculation( - rewardRate, - totalWeightedStake, - StakeDurations.findIndex((duration) => { - return duration == Number(poolInfo.duration) / OneMonth; - }), - )} - % - -
-
- Time Left - - {getTimeLeftString(Number(poolInfo.unStakeAt) * 1000)} - -
-
- - UNSTAKE - -
-
- - CLAIM{" "} - {Number( - formatUnits(BigInt(rewardsArray ? rewardsArray[poolIndex] : 0), ldyTokenDecimals!), - ).toFixed(4)}{" "} - Token - -
-
-
-
+
+ + + Allow Ledgity Yield to use{" "} + + + } + queryKeys={[allowanceQueryKey]} + {...props} + > + Allow + +
); -}; \ No newline at end of file +};