import { useState, useCallback, useEffect } from 'react' import { useAccount, useWriteContract, useWaitForTransactionReceipt, useReadContract } from 'wagmi' import { parseUnits, formatUnits } from 'viem' import { abis, getContractAddress } from '@/lib/contracts' import { useTokenList } from './useTokenList' import { handleContractCatchError, isValidAmount, parseContractError } from '@/lib/errors' type SupplyStatus = 'idle' | 'approving' | 'approved' | 'supplying' | 'success' | 'error' export function useLendingSupply() { 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: supplyWrite, data: supplyHash, isPending: isSupplyPending, reset: resetSupply, } = useWriteContract() const { isLoading: isSupplyConfirming, isSuccess: isSupplySuccess, isError: isSupplyError, error: supplyReceiptError, } = useWaitForTransactionReceipt({ hash: supplyHash }) const executeApprove = useCallback(async (amount: string) => { if (status !== 'idle') return false if (!address || !chainId || !usdcToken?.contractAddress || !amount) { setError('Missing required parameters') return false } if (!isValidAmount(amount)) { setError('Invalid amount') return false } try { setError(null) setStatus('approving') const lendingProxyAddress = getContractAddress('lendingProxy', chainId) if (!lendingProxyAddress) { throw new Error('Contract not deployed on this chain') } 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: [lendingProxyAddress, amountInWei], }) return true } catch (err: unknown) { handleContractCatchError(err, 'Approve failed', setError, setStatus as (s: string) => void) return false } }, [address, chainId, approveWrite, usdcToken, status]) const executeSupply = useCallback(async (amount: string) => { if (status === 'supplying' || status === 'success' || status === 'error') return false if (!address || !chainId || !usdcToken || !amount) { setError('Missing required parameters') return false } if (!isValidAmount(amount)) { setError('Invalid amount') return false } try { setError(null) setStatus('supplying') const lendingProxyAddress = getContractAddress('lendingProxy', chainId) if (!lendingProxyAddress) { throw new Error('Contract not deployed on this chain') } const usdcDecimals = usdcToken.onChainDecimals ?? usdcToken.decimals const amountInWei = parseUnits(amount, usdcDecimals) await supplyWrite({ address: lendingProxyAddress, abi: abis.lendingProxy, functionName: 'supply', args: [amountInWei], }) return true } catch (err: unknown) { handleContractCatchError(err, 'Supply failed', setError, setStatus as (s: string) => void) return false } }, [address, chainId, supplyWrite, usdcToken, status]) const executeApproveAndSupply = useCallback(async (amount: string) => { if (status !== 'idle') return setPendingAmount(amount) const approveSuccess = await executeApprove(amount) if (!approveSuccess) return }, [executeApprove, status]) // Auto-execute supply when approve is successful useEffect(() => { if (isApproveSuccess && status === 'approving' && pendingAmount) { setStatus('approved') executeSupply(pendingAmount) } }, [isApproveSuccess, status, pendingAmount, executeSupply]) useEffect(() => { if (isApproveError && status === 'approving') { setError(parseContractError(approveReceiptError)) setStatus('error') } }, [isApproveError, status, approveReceiptError]) useEffect(() => { if (isSupplySuccess && status === 'supplying') { setStatus('success') } }, [isSupplySuccess, status]) useEffect(() => { if (isSupplyError && status === 'supplying') { setError(parseContractError(supplyReceiptError)) setStatus('error') } }, [isSupplyError, status, supplyReceiptError]) const reset = useCallback(() => { setStatus('idle') setError(null) setPendingAmount('') resetApprove() resetSupply() }, [resetApprove, resetSupply]) return { status, error, isLoading: isApprovePending || isApproveConfirming || isSupplyPending || isSupplyConfirming, approveHash, supplyHash, executeApprove, executeSupply, executeApproveAndSupply, reset, } } // Query supplied balance export function useSuppliedBalance() { const { address, chainId } = useAccount() const { bySymbol } = useTokenList() const usdcToken = bySymbol['USDC'] const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined const { data: balance, error: queryError, isError, isLoading, refetch } = useReadContract({ address: lendingProxyAddress, abi: abis.lendingProxy, functionName: 'supplyBalanceOf', args: address ? [address] : undefined, query: { enabled: !!address && !!lendingProxyAddress, retry: false, }, }) if (isError && queryError) { console.error('[useSuppliedBalance] Query error:', queryError) } const usdcDecimals = usdcToken?.onChainDecimals ?? usdcToken?.decimals ?? 18 const suppliedBalance = balance ? (balance as bigint) : 0n const formattedBalance = suppliedBalance > 0n ? (Number(suppliedBalance) / Math.pow(10, usdcDecimals)).toFixed(2) : '0.00' return { balance: suppliedBalance, formattedBalance, refetch, } }