"use client"; import { useApp } from "@/contexts/AppContext"; import { useReadContract, useReadContracts } from "wagmi"; import { useAccount } from "wagmi"; import { formatUnits } from "viem"; import { abis, getContractAddress } from "@/lib/contracts"; import { useTokenBySymbol } from "@/hooks/useTokenBySymbol"; import { useTokenList } from "@/hooks/useTokenList"; interface LendingHeaderProps { market: 'USDC' | 'USDT'; } export default function LendingHeader({ market }: LendingHeaderProps) { const { t } = useApp(); const { chainId } = useAccount(); const lendingProxyAddress = chainId ? getContractAddress('lendingProxy', chainId) : undefined; const usdcToken = useTokenBySymbol('USDC'); const usdcDecimals = usdcToken?.onChainDecimals ?? usdcToken?.decimals ?? 18; // 链上总供应量 const { data: totalSupply } = useReadContract({ address: lendingProxyAddress, abi: abis.lendingProxy, functionName: 'getTotalSupply', query: { enabled: !!lendingProxyAddress }, }); // 链上利用率(1e18 精度) const { data: utilization } = useReadContract({ address: lendingProxyAddress, abi: abis.lendingProxy, functionName: 'getUtilization', query: { enabled: !!lendingProxyAddress }, }); // 全市场抵押品总量(USD) // 用 ERC20.balanceOf(lendingProxy) 获取合约实际持有的 YT token 数量 // (用户存入的抵押品都在合约里,这是最准确的总量) const { yieldTokens } = useTokenList(); const ytAddresses = yieldTokens.map(t => t.contractAddress).filter(Boolean) as `0x${string}`[]; const erc20BalanceAbi = [{ name: 'balanceOf', type: 'function', stateMutability: 'view', inputs: [{ name: 'account', type: 'address' }], outputs: [{ name: '', type: 'uint256' }], }] as const; // 批量读每个 YT token 合约里 lendingProxy 的余额 const { data: balancesData } = useReadContracts({ contracts: ytAddresses.map(addr => ({ address: addr, abi: erc20BalanceAbi, functionName: 'balanceOf' as const, args: [lendingProxyAddress as `0x${string}`], chainId, })), query: { enabled: !!lendingProxyAddress && ytAddresses.length > 0 }, }); // 批量读每个 YT token 的价格(30 位精度) const { data: pricesData } = useReadContracts({ contracts: ytAddresses.map(addr => ({ address: addr as `0x${string}`, abi: abis.YTToken as any, functionName: 'ytPrice' as const, args: [], chainId, })), query: { enabled: ytAddresses.length > 0 }, }); // 计算总抵押品 USD 价值:Σ(balance[i] / 1e18 * price[i] / 1e30) const totalCollateralUSD = (() => { if (!balancesData || !pricesData) return null; let sum = 0; ytAddresses.forEach((_, i) => { const bal = balancesData[i]; const pri = pricesData[i]; if (bal?.status !== 'success' || pri?.status !== 'success') return; const balance = Number(formatUnits(bal.result as bigint, 18)); const price = Number(formatUnits(pri.result as bigint, 30)); sum += balance * price; }); return sum; })(); const displayTotalCollateral = totalCollateralUSD !== null ? `$${totalCollateralUSD.toLocaleString('en-US', { maximumFractionDigits: 2 })}` : '--'; // 格式化总供应量 const displaySupply = totalSupply != null ? `$${parseFloat(formatUnits(totalSupply as bigint, usdcDecimals)).toLocaleString('en-US', { maximumFractionDigits: 2 })}` : '--'; // 格式化利用率 const displayUtilization = utilization != null ? `${(Number(formatUnits(utilization as bigint, 18)) * 100).toFixed(1)}%` : '--'; const stats = [ { label: t("lending.totalUsdcSupply"), value: displaySupply, valueColor: "text-text-primary dark:text-white", }, { label: t("lending.utilization"), value: displayUtilization, valueColor: "text-[#10b981] dark:text-green-400", }, { label: t("lending.totalCollateral"), value: displayTotalCollateral, valueColor: "text-text-primary dark:text-white", }, ]; return (
{t("lending.subtitle")}