import { useState, useCallback, useEffect } from 'react' import { useAccount, useWriteContract, useWaitForTransactionReceipt } from 'wagmi' import { parseUnits } from 'viem' import { abis } from '@/lib/contracts' import { Token } from '@/lib/api/tokens' import { useTokenList } from './useTokenList' import { handleContractCatchError, isValidAmount, parseContractError } from '@/lib/errors' import { DEFAULT_GAS_LIMIT } from '@/lib/constants' type DepositStatus = 'idle' | 'approving' | 'approved' | 'depositing' | 'success' | 'error' export function useDeposit(ytToken: Token | undefined) { const { address, chainId } = useAccount() const { bySymbol } = useTokenList() const usdcToken = bySymbol['USDC'] const [status, setStatus] = useState('idle') const [error, setError] = useState(null) const [pendingAmount, setPendingAmount] = useState('') const { writeContractAsync: approveWrite, data: approveHash, isPending: isApprovePending, reset: resetApprove, } = useWriteContract() const { isLoading: isApproveConfirming, isSuccess: isApproveSuccess, isError: isApproveError, error: approveReceiptError, } = useWaitForTransactionReceipt({ hash: approveHash }) const { writeContractAsync: depositWrite, data: depositHash, isPending: isDepositPending, reset: resetDeposit, } = useWriteContract() const { isLoading: isDepositConfirming, isSuccess: isDepositSuccess, isError: isDepositError, error: depositReceiptError, } = useWaitForTransactionReceipt({ hash: depositHash }) const executeApprove = useCallback(async (amount: string) => { if (status !== 'idle') return false if (!address || !ytToken?.contractAddress || !usdcToken?.contractAddress || !amount) { setError('Missing required parameters') return false } if (!isValidAmount(amount)) { setError('Invalid amount') return false } try { setError(null) setStatus('approving') const usdcDecimals = usdcToken.onChainDecimals ?? usdcToken.decimals const amountInWei = parseUnits(amount, usdcDecimals) await approveWrite({ address: usdcToken.contractAddress as `0x${string}`, abi: abis.USDY, functionName: 'approve', args: [ytToken.contractAddress as `0x${string}`, amountInWei], }) return true } catch (err: unknown) { handleContractCatchError(err, 'Approve failed', setError, setStatus as (s: string) => void) return false } }, [address, approveWrite, ytToken, usdcToken, status]) const executeDeposit = useCallback(async (amount: string) => { if (status === 'depositing' || status === 'success' || status === 'error') return false if (!address || !ytToken?.contractAddress || !usdcToken || !amount) { setError('Missing required parameters') return false } if (!isValidAmount(amount)) { setError('Invalid amount') return false } try { setError(null) setStatus('depositing') const usdcDecimals = usdcToken.onChainDecimals ?? usdcToken.decimals const amountInWei = parseUnits(amount, usdcDecimals) await depositWrite({ address: ytToken.contractAddress as `0x${string}`, abi: abis.YTToken, functionName: 'depositYT', args: [amountInWei], gas: DEFAULT_GAS_LIMIT, }) return true } catch (err: unknown) { handleContractCatchError(err, 'Deposit failed', setError, setStatus as (s: string) => void) return false } }, [address, depositWrite, ytToken, usdcToken, status]) const executeApproveAndDeposit = useCallback(async (amount: string) => { if (status !== 'idle') return setPendingAmount(amount) const approveSuccess = await executeApprove(amount) if (!approveSuccess) return }, [executeApprove, status]) // Auto-execute deposit when approve is successful useEffect(() => { if (isApproveSuccess && status === 'approving' && pendingAmount) { setStatus('approved') executeDeposit(pendingAmount) } }, [isApproveSuccess, status, pendingAmount, executeDeposit]) useEffect(() => { if (isApproveError && status === 'approving') { setError(parseContractError(approveReceiptError)) setStatus('error') } }, [isApproveError, status, approveReceiptError]) useEffect(() => { if (isDepositSuccess && status === 'depositing') { setStatus('success') } }, [isDepositSuccess, status]) useEffect(() => { if (isDepositError && status === 'depositing') { setError(parseContractError(depositReceiptError)) setStatus('error') } }, [isDepositError, status, depositReceiptError]) const reset = useCallback(() => { setStatus('idle') setError(null) setPendingAmount('') resetApprove() resetDeposit() }, [resetApprove, resetDeposit]) return { status, error, isLoading: isApprovePending || isApproveConfirming || isDepositPending || isDepositConfirming, approveHash, depositHash, executeApprove, executeDeposit, executeApproveAndDeposit, reset, } }