import { useState, useEffect } from 'react' import { type Address } from 'viem' import { useTranslations } from 'next-intl' import { useAppDispatch } from '@/store/hooks' import { fetchAndStoreSingleNetworkPortfolioBalances, usePortfolioState, } from '@/slices/portfolio/hooks' import { usePendingTxWrapper } from '@/utils/hooks/usePendingTxWrapper' import { getTokenAllowance } from '@/utils/actions/getTokenAllowance' import { getStakedBalance } from '@/utils/actions/getStakedBalance' import { approve, stake } from '@/utils/actions/approveAndStake' import { withdrawStake } from '@/utils/actions/withdrawStake' import { getTokenOnChain } from '@/utils/hooks/useTokenInfo' import { cleanNumberInput } from '@/utils/cleanNumberInput' import { claimStake } from '@/utils/actions/claimStake' import { formatBigIntToString } from '@/utils/bigint/format' import { stringToBigInt } from '@/utils/bigint/format' import { Token } from '@/utils/types' import { InteractiveInputRowButton } from '@/components/InteractiveInputRowButton' import { trimTrailingZeroesAfterDecimal } from '@/utils/trimTrailingZeroesAfterDecimal' import ButtonLoadingDots from '@/components/buttons/ButtonLoadingDots' import InteractiveInputRow from '@/components/InteractiveInputRow' import Button from '@/components/ui/tailwind/Button' import TabItem from '@/components/ui/tailwind/TabItem' import Tabs from '@/components/ui/tailwind/Tabs' import InfoSectionCard from '../pool/PoolInfoSection/InfoSectionCard' import StakeCardTitle from './StakeCardTitle' interface StakeCardProps { address: string chainId: number pool: Token } const StakeCard = ({ address, chainId, pool }: StakeCardProps) => { const dispatch = useAppDispatch() const tokenInfo = getTokenOnChain(chainId, pool) const stakingPoolLabel: string = tokenInfo?.poolName const stakingPoolTokens: Token[] = tokenInfo?.poolTokens const stakingPoolId: number = tokenInfo?.poolId const t = useTranslations('Pools') const { poolTokenBalances } = usePortfolioState() const lpTokenBalance = poolTokenBalances[chainId]?.find( (tokenBalance) => tokenBalance.tokenAddress === pool.addresses[chainId] )?.balance const [deposit, setDeposit] = useState({ str: '', bi: 0n }) const [withdraw, setWithdraw] = useState('') const [showStake, setShowStake] = useState(true) const [allowance, setAllowance] = useState(0n) const [isPending, pendingTxWrapFunc] = usePendingTxWrapper() const [isPendingStake, pendingStakeTxWrapFunc] = usePendingTxWrapper() const [isPendingUnstake, pendingUnstakeTxWrapFunc] = usePendingTxWrapper() const [isPendingApprove, pendingApproveTxWrapFunc] = usePendingTxWrapper() const [userStakeData, setUserStakeData] = useState({ amount: 0n, reward: 0n, }) const miniChefAddress = pool.miniChefAddress const resetUserStakeData = () => { setUserStakeData({ amount: 0n, reward: 0n, }) } const getUserStakedBalance = async ( address: Address, stakingPoolId: number, pool: Token ) => { try { const data = await getStakedBalance( address as Address, pool.chainId, stakingPoolId, pool ) setUserStakeData(data) } catch (err) { console.error('Error fetching user staked balance:', err) } } const getUserLpTokenAllowance = async ( address: Address, chainId: number, pool: Token ) => { try { const tkAllowance = await getTokenAllowance( miniChefAddress as Address, pool.addresses[chainId] as Address, address as Address, chainId ) setAllowance(tkAllowance) } catch (err) { console.error('Error fetching user LP token allowance:', err) } } useEffect(() => { if (!address || !chainId || stakingPoolId === null) { resetUserStakeData() return } getUserStakedBalance(address as Address, stakingPoolId, pool) }, [address, chainId, stakingPoolId]) useEffect(() => { if (!address) { resetUserStakeData() return } getUserLpTokenAllowance(address as Address, chainId, pool) getUserStakedBalance(address as Address, stakingPoolId, pool) }, [lpTokenBalance]) useEffect(() => { if (!address) return getUserLpTokenAllowance(address as Address, chainId, pool) }, [deposit]) return (
{t('Unstaked')}
{!lpTokenBalance ? '\u2212' : trimTrailingZeroesAfterDecimal( formatBigIntToString(lpTokenBalance, tokenInfo.decimals, 6) )}{' '} {pool ? pool.symbol : ''}
{t('Staked')}
{trimTrailingZeroesAfterDecimal( formatBigIntToString(userStakeData.amount, tokenInfo.decimals, 6) )}{' '} {pool ? pool.symbol : ''}
{pool?.customRewardToken ?? 'SYN'} {t('Earned')}
{!userStakeData.reward ? '\u2212' : trimTrailingZeroesAfterDecimal( formatBigIntToString(userStakeData.reward, 18, 6) )}{' '} {pool?.customRewardToken ?? 'SYN'}
{!userStakeData.reward ? null : ( )}
{ setShowStake(true) }} className="rounded-tl-sm" > {t('Stake')} { setShowStake(false) }} className="rounded-tr-sm" > {t('Unstake')}
{showStake ? ( { setDeposit({ str: !lpTokenBalance ? '0.0000' : trimTrailingZeroesAfterDecimal( formatBigIntToString(lpTokenBalance, tokenInfo.decimals) ), bi: lpTokenBalance, }) }} value={deposit.str} placeholder={'0.0000'} onChange={async (e) => { let val = cleanNumberInput(e.target.value) setDeposit({ str: val, bi: stringToBigInt(val, pool.decimals[chainId]), }) }} disabled={!lpTokenBalance} icon={pool?.icon?.src} /> ) : ( { setWithdraw( !userStakeData.amount ? '0.00000' : trimTrailingZeroesAfterDecimal( formatBigIntToString( userStakeData.amount, tokenInfo.decimals, 18 ) ) ) }} value={withdraw} placeholder={'0.0000'} onChange={(e) => { let val = cleanNumberInput(e.target.value) setWithdraw(val) }} disabled={!userStakeData.amount} icon={pool?.icon?.src} /> )} {showStake ? ( { const tx = await pendingApproveTxWrapFunc( approve(pool, deposit.bi, chainId) ) if (tx?.status === 'success') { getUserLpTokenAllowance( address as Address, chainId, pool ) } } : async (e) => { const tx = await pendingStakeTxWrapFunc( stake( address as Address, chainId, stakingPoolId, pool, deposit.bi ) ) if (tx?.status === 'success') { setDeposit({ bi: 0n, str: '' }) dispatch( fetchAndStoreSingleNetworkPortfolioBalances({ address, chainId, }) ) } } } /> ) : ( { const tx = await pendingUnstakeTxWrapFunc( withdrawStake( address as Address, chainId, stakingPoolId, pool, stringToBigInt(withdraw, 18) ) ) if (tx?.status === 'success') { setWithdraw('') dispatch( fetchAndStoreSingleNetworkPortfolioBalances({ address, chainId, }) ) } }} /> )}
) } export default StakeCard