Files
web/src/hooks/usePartyPlanner.ts

937 lines
30 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { usePublicClient } from 'wagmi';
import chainInfo from '@/contracts/liqp-deployments.json';
import IPartyPlannerABI from '@/contracts/IPartyPlannerABI';
import IPartyPoolABI from '@/contracts/IPartyPoolABI';
import IPartyPoolViewerABI from '@/contracts/IPartyPoolViewerABI';
import IPartyInfoABI from '@/contracts/IPartyInfoABI';
import { ERC20ABI } from '@/contracts/ERC20ABI';
// Helper function to format large numbers with K, M, B suffixes
function formatTVL(value: number): string {
if (value >= 1_000_000_000) {
return `$${(value / 1_000_000_000).toFixed(2)}B`;
} else if (value >= 1_000_000) {
return `$${(value / 1_000_000).toFixed(2)}M`;
} else if (value >= 1_000) {
return `$${(value / 1_000).toFixed(2)}K`;
} else {
return `$${value.toFixed(2)}`;
}
}
export function useGetAllTokens(offset: number = 0, limit: number = 100) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [tokens, setTokens] = useState<readonly `0x${string}`[] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted) return;
const fetchTokens = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
// Get chain ID and contract address
const chainId = await publicClient.getChainId();
// @ts-ignore
const address = (chainInfo as Record<string, { v1: { PartyPlanner: string } }>)[chainId.toString()]?.v1?.PartyPlanner;
if (!address) {
setError('IPartyPlanner contract not found for current chain');
setTokens([]);
return;
}
// Call getAllTokens function
const result = await publicClient.readContract({
address: address as `0x${string}`,
abi: IPartyPlannerABI,
functionName: 'getAllTokens',
args: [BigInt(offset), BigInt(limit)],
});
setTokens(result);
} catch (err) {
console.error('Error calling getAllTokens:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch tokens');
} finally {
setLoading(false);
}
};
fetchTokens();
}, [publicClient, mounted, offset, limit]);
return {
tokens,
loading,
error,
isReady: mounted,
};
}
export interface TokenDetails {
address: `0x${string}`;
name: string;
symbol: string;
decimals: number;
balance: bigint;
index: number;
}
export interface SwapRoute {
poolAddress: `0x${string}`;
inputTokenIndex: number;
outputTokenIndex: number;
}
export interface AvailableToken {
address: `0x${string}`;
symbol: string;
swapRoutes: SwapRoute[];
}
export function useGetPoolsByToken(tokenAddress: `0x${string}` | undefined, offset: number = 0, limit: number = 100) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [availableTokens, setAvailableTokens] = useState<AvailableToken[] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !tokenAddress) {
setLoading(false);
return;
}
const fetchPoolsFromTokens = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
// Get chain ID and contract addresses
const chainId = await publicClient.getChainId();
const plannerAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyPlanner;
const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!plannerAddress || !partyInfoAddress) {
setError('IPartyPlanner or PartyInfo contract not found for current chain');
setAvailableTokens([]);
return;
}
// Call getPoolsByToken function
const poolsResult = await publicClient.readContract({
address: plannerAddress as `0x${string}`,
abi: IPartyPlannerABI,
functionName: 'getPoolsByToken',
args: [tokenAddress, BigInt(offset), BigInt(limit)],
});
// Get the symbol of the originally selected token
const selectedTokenSymbol = await publicClient.readContract({
address: tokenAddress,
abi: ERC20ABI,
functionName: 'symbol',
}).catch(() => null);
if (!selectedTokenSymbol) {
setAvailableTokens([]);
return;
}
// Filter pools to only working ones
const workingPools: `0x${string}`[] = [];
for (const poolAddress of poolsResult) {
try {
const isWorking = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyInfoABI,
functionName: 'working',
args: [poolAddress],
}) as boolean;
if (isWorking) {
workingPools.push(poolAddress);
}
} catch (err) {
console.error(`Error checking if pool ${poolAddress} is working:`, err);
}
}
// If no working pools found, set error message
if (workingPools.length === 0 && poolsResult.length > 0) {
setError('This token is no longer supported. All pools containing this token are currently inactive.');
setAvailableTokens([]);
return;
} else if (workingPools.length === 0) {
setError('No pools found for this token.');
setAvailableTokens([]);
return;
}
// Map to store available tokens with their swap routes
const tokenRoutesMap = new Map<string, AvailableToken>();
// For each working pool, fetch all tokens and track indices
for (const poolAddress of workingPools) {
try {
const tokensInPool = await publicClient.readContract({
address: poolAddress,
abi: IPartyPoolABI,
functionName: 'allTokens',
}) as readonly `0x${string}`[];
// Find the input token index in this pool
const inputTokenIndex = tokensInPool.findIndex(
(token) => token.toLowerCase() === tokenAddress.toLowerCase()
);
if (inputTokenIndex === -1) {
console.error('Input token not found in pool', poolAddress);
continue;
}
// Process each token in the pool
for (let outputTokenIndex = 0; outputTokenIndex < tokensInPool.length; outputTokenIndex++) {
const outputTokenAddress = tokensInPool[outputTokenIndex];
// Skip if it's the same as the input token
if (outputTokenIndex === inputTokenIndex) {
continue;
}
// Get the symbol of this token
const outputTokenSymbol = await publicClient.readContract({
address: outputTokenAddress,
abi: ERC20ABI,
functionName: 'symbol',
}).catch(() => null);
// Skip tokens with the same symbol as the selected token
if (!outputTokenSymbol || outputTokenSymbol === selectedTokenSymbol) {
continue;
}
// Create or update the available token entry
const tokenKey = outputTokenAddress.toLowerCase();
if (!tokenRoutesMap.has(tokenKey)) {
tokenRoutesMap.set(tokenKey, {
address: outputTokenAddress,
symbol: outputTokenSymbol,
swapRoutes: [],
});
}
// Add this swap route
tokenRoutesMap.get(tokenKey)!.swapRoutes.push({
poolAddress,
inputTokenIndex,
outputTokenIndex,
});
}
} catch (err) {
console.error('Error fetching tokens from pool', poolAddress, err);
}
}
const availableTokensList = Array.from(tokenRoutesMap.values());
setAvailableTokens(availableTokensList);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch pools and tokens');
} finally {
setLoading(false);
}
};
fetchPoolsFromTokens();
}, [publicClient, mounted, tokenAddress, offset, limit]);
return {
availableTokens,
loading,
error,
isReady: mounted,
};
}
export function useTokenDetails(userAddress: `0x${string}` | undefined) {
const publicClient = usePublicClient();
const { tokens, loading: tokensLoading, isReady } = useGetAllTokens();
const [tokenDetails, setTokenDetails] = useState<TokenDetails[] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!isReady || tokensLoading || !tokens || !publicClient || !userAddress) {
setLoading(tokensLoading || !isReady);
return;
}
const fetchTokenDetails = async () => {
try {
setLoading(true);
setError(null);
if (tokens.length === 0) {
setTokenDetails([]);
return;
}
const details: TokenDetails[] = [];
// Make individual calls for each token
for (let i = 0; i < tokens.length; i++) {
const tokenAddress = tokens[i];
try {
const [name, symbol, decimals, balance] = await Promise.all([
publicClient.readContract({
address: tokenAddress,
abi: ERC20ABI,
functionName: 'name',
}).catch(() => 'Unknown'),
publicClient.readContract({
address: tokenAddress,
abi: ERC20ABI,
functionName: 'symbol',
}).catch(() => '???'),
publicClient.readContract({
address: tokenAddress,
abi: ERC20ABI,
functionName: 'decimals',
}).catch(() => 18),
publicClient.readContract({
address: tokenAddress,
abi: ERC20ABI,
functionName: 'balanceOf',
args: [userAddress],
}).catch(() => BigInt(0)),
]);
details.push({
address: tokenAddress,
name: name as string,
symbol: symbol as string,
decimals: Number(decimals),
balance: balance as bigint,
index: i,
});
} catch (err) {
// Add token with fallback values if individual call fails
details.push({
address: tokenAddress,
name: 'Unknown',
symbol: '???',
decimals: 18,
balance: BigInt(0),
index: i,
});
}
}
setTokenDetails(details);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch token details');
} finally {
setLoading(false);
}
};
fetchTokenDetails();
}, [tokens, tokensLoading, publicClient, isReady, userAddress]);
return {
tokenDetails,
loading,
error,
};
}
export interface PoolDetails {
address: `0x${string}`;
name: string;
symbol: string;
tokens: readonly `0x${string}`[];
price?: string; // Formatted price string
tvl?: string; // Formatted TVL string (e.g., "$1.2M")
isKilled: boolean; // Whether the pool has been killed
}
export function useGetAllPools(offset: number = 0, limit: number = 100) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [pools, setPools] = useState<readonly `0x${string}`[] | null>(null);
const [poolDetails, setPoolDetails] = useState<PoolDetails[] | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted) return;
const fetchPools = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
// Get chain ID and contract addresses
const chainId = await publicClient.getChainId();
const plannerAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyPlanner;
const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!plannerAddress || !partyInfoAddress) {
setError('IPartyPlanner or PartyInfo contract not found for current chain');
setPools([]);
setPoolDetails([]);
return;
}
// Call getAllPools function
const result = await publicClient.readContract({
address: plannerAddress as `0x${string}`,
abi: IPartyPlannerABI,
functionName: 'getAllPools',
args: [BigInt(offset), BigInt(limit)],
});
setPools(result);
// Fetch details for each pool and check if it's working
const details: PoolDetails[] = [];
for (const poolAddress of result) {
try {
const [name, symbol, tokens, isWorking] = await Promise.all([
publicClient.readContract({
address: poolAddress,
abi: ERC20ABI,
functionName: 'name',
}).catch(() => 'Unknown Pool'),
publicClient.readContract({
address: poolAddress,
abi: ERC20ABI,
functionName: 'symbol',
}).catch(() => 'POOL'),
publicClient.readContract({
address: poolAddress,
abi: IPartyPoolABI,
functionName: 'allTokens',
}).catch(() => [] as readonly `0x${string}`[]),
publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyInfoABI,
functionName: 'working',
args: [poolAddress],
}).catch(() => false),
]);
// Fetch pool price and TVL (only for working pools)
let priceStr: string | undefined;
let tvlStr: string | undefined;
if (isWorking) {
// Fetch pool price (use first token as quote, index 0)
try {
const priceRaw = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyInfoABI,
functionName: 'poolPrice',
args: [poolAddress, BigInt(0)],
});
const price = BigInt(priceRaw as bigint | number);
if (price === 0n) {
priceStr = undefined;
} else {
// Convert Q64 format to decimal (price = priceValue / 2^64)
const Q64 = 2n ** 64n;
const isNegative = price < 0n;
const absPrice = isNegative ? -price : price;
const priceFloat = Number(absPrice) / Number(Q64);
const finalPrice = isNegative ? -priceFloat : priceFloat;
priceStr = `$${finalPrice.toFixed(4)}`;
}
} catch (err) {
console.error(`Error fetching pool price for ${poolAddress}:`, err);
priceStr = undefined;
}
// Calculate TVL (approximate by getting first token balance and doubling it)
try {
if (tokens && tokens.length > 0) {
const firstTokenAddress = tokens[0];
// Get token decimals and balance
const [decimals, balance] = await Promise.all([
publicClient.readContract({
address: firstTokenAddress as `0x${string}`,
abi: ERC20ABI,
functionName: 'decimals',
}) as Promise<number>,
publicClient.readContract({
address: firstTokenAddress as `0x${string}`,
abi: ERC20ABI,
functionName: 'balanceOf',
args: [poolAddress],
}) as Promise<bigint>,
]);
// Convert balance to float and double it for total TVL approximation
const tokenBalance = Number(balance) / Math.pow(10, decimals);
const approximateTVL = tokenBalance * 3;
tvlStr = formatTVL(approximateTVL);
}
} catch (err) {
console.error(`Error fetching TVL for ${poolAddress}:`, err);
tvlStr = undefined;
}
}
// Add all pools (both working and killed)
details.push({
address: poolAddress,
name: name as string,
symbol: symbol as string,
tokens: tokens as readonly `0x${string}`[],
price: priceStr,
tvl: tvlStr,
isKilled: !isWorking,
});
} catch (err) {
console.error('Error fetching pool details for', poolAddress, err);
// Skip pools that fail to load
}
}
setPoolDetails(details);
} catch (err) {
console.error('Error calling getAllPools:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch pools');
} finally {
setLoading(false);
}
};
fetchPools();
}, [publicClient, mounted, offset, limit]);
return {
pools,
poolDetails,
loading,
error,
isReady: mounted,
};
}
export interface SwapMintAmounts {
amountInUsed: bigint;
fee: bigint;
lpMinted: bigint;
calculatedSlippage?: number; // Percentage, e.g. 5.5 means 5.5%
}
export interface BurnSwapAmounts {
amountOut: bigint;
outFee: bigint;
calculatedSlippage?: number; // Percentage, e.g. 5.5 means 5.5%
}
export function useSwapMintAmounts(
poolAddress: `0x${string}` | undefined,
inputTokenIndex: number | undefined,
maxAmountIn: bigint | undefined,
inputTokenDecimals: number | undefined // Decimals of the input token
) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [swapMintAmounts, setSwapMintAmounts] = useState<SwapMintAmounts | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !poolAddress || inputTokenIndex === undefined || !maxAmountIn || maxAmountIn === BigInt(0)) {
setLoading(false);
setSwapMintAmounts(null);
return;
}
const fetchSwapMintAmounts = async () => {
if (!publicClient) return;
// Early validation
if (inputTokenDecimals === undefined) {
setError('inputTokenDecimals is required but was undefined');
return;
}
try {
setLoading(true);
setError(null);
const chainId = await publicClient.getChainId();
const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!partyInfoAddress) {
setError('PartyInfo contract not found for current chain');
setSwapMintAmounts(null);
return;
}
const result = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyPoolViewerABI,
functionName: 'swapMintAmounts',
args: [poolAddress, BigInt(inputTokenIndex), maxAmountIn],
}) as readonly [bigint, bigint, bigint];
// Fetch and calculate pool price
let poolPrice: number | undefined;
let calculatedSlippage: number | undefined;
try {
console.log('input token index', inputTokenIndex);
const poolPriceInt128 = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyInfoABI,
functionName: 'poolPrice',
args: [poolAddress, BigInt(inputTokenIndex)],
}) as bigint;
const basePrice = Number(poolPriceInt128) / (2 ** 64);
poolPrice = 1 / (basePrice * Math.pow(10, 18 - inputTokenDecimals));
// Calculate slippage
const decimalsMultiplier = Math.pow(10, inputTokenDecimals);
const lpMinted = Number(result[1]) / Math.pow(10, 18);
const amountIn = Number(result[0]) / decimalsMultiplier;
const fee = Number(result[2]) / decimalsMultiplier;
const swapPrice = lpMinted / (amountIn - fee);
calculatedSlippage = ((poolPrice - swapPrice) / poolPrice) * 100;
} catch (priceErr) {
console.error('Error fetching poolPrice or calculating slippage:', priceErr);
}
setSwapMintAmounts({
amountInUsed: result[0],
fee: result[2],
lpMinted: result[1],
calculatedSlippage,
});
} catch (err) {
console.error('Error calling swapMintAmounts:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch swap mint amounts');
setSwapMintAmounts(null);
} finally {
setLoading(false);
}
};
fetchSwapMintAmounts();
}, [publicClient, mounted, poolAddress, inputTokenIndex, maxAmountIn, inputTokenDecimals]);
return {
swapMintAmounts,
loading,
error,
isReady: mounted,
};
}
export function useBurnSwapAmounts(
poolAddress: `0x${string}` | undefined,
lpAmount: bigint | undefined,
inputTokenIndex: number | undefined,
tokenDecimals: number | undefined // Decimals of the output token
) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [burnSwapAmounts, setBurnSwapAmounts] = useState<BurnSwapAmounts | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !poolAddress || !lpAmount || lpAmount === BigInt(0) || inputTokenIndex === undefined) {
setLoading(false);
setBurnSwapAmounts(null);
return;
}
const fetchBurnSwapAmounts = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
console.log('fetching swap amounts')
// Get chain ID and contract address
const chainId = await publicClient.getChainId();
// @ts-ignore
const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!partyInfoAddress) {
console.log('errores here')
setError('PartyInfo contract not found for current chain');
setBurnSwapAmounts(null);
return;
}
// Call burnSwapAmounts function - returns [amountOut, outFee]
const result = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyPoolViewerABI,
functionName: 'burnSwapAmounts',
args: [poolAddress, lpAmount, BigInt(inputTokenIndex)],
}) as readonly [bigint, bigint];
// Calculate slippage for burnSwap using poolPrice
let calculatedSlippage: number | undefined;
if (tokenDecimals !== undefined) {
try {
// Get the market price from poolPrice (quoteTokenIndex = 0)
const poolPriceInt128 = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyInfoABI,
functionName: 'poolPrice',
args: [poolAddress, BigInt(inputTokenIndex)],
}) as bigint;
// Convert Q64 format to decimal (price = priceValue / 2^64)
let poolPrice = Number(poolPriceInt128) / 2 ** 64;
poolPrice = (poolPrice * Math.pow(10, 18 - tokenDecimals));
// For burnSwap: swapPrice = (outAmount + fee) / lpAmount
// Need to apply decimal corrections: outAmount and fee are in token decimals, lpAmount is in 18 decimals
const outAmountDecimal = Number(result[0]) / Math.pow(10, tokenDecimals);
const feeDecimal = Number(result[1]) / Math.pow(10, tokenDecimals);
const lpAmountDecimal = Number(lpAmount) / Math.pow(10, 18); // LP tokens have 18 decimals
const swapPrice = (outAmountDecimal + feeDecimal) / lpAmountDecimal;
calculatedSlippage = ((poolPrice - swapPrice) / poolPrice) * 100;
console.log('burnSwap slippage calculation:', {
poolPrice,
swapPrice,
calculatedSlippage,
outAmountDecimal,
feeDecimal,
lpAmountDecimal,
outAmount: result[0].toString(),
fee: result[1].toString(),
lpAmount: lpAmount.toString(),
});
} catch (slippageErr) {
console.error(`Error calculating slippage for burnSwap:`, slippageErr);
}
}
const parsedAmounts = {
amountOut: result[0],
outFee: result[1],
calculatedSlippage,
};
setBurnSwapAmounts(parsedAmounts);
} catch (err) {
console.error('Error calling burnSwapAmounts:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch burn swap amounts');
setBurnSwapAmounts(null);
} finally {
setLoading(false);
}
};
fetchBurnSwapAmounts();
}, [publicClient, mounted, poolAddress, lpAmount, inputTokenIndex, tokenDecimals]);
return {
burnSwapAmounts,
loading,
error,
isReady: mounted,
};
}
export function useLPTokenBalance(
poolAddress: `0x${string}` | undefined,
userAddress: `0x${string}` | undefined
) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [lpBalance, setLpBalance] = useState<bigint | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Handle hydration for Next.js static export
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !poolAddress || !userAddress) {
setLoading(false);
setLpBalance(null);
return;
}
const fetchLPBalance = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
// Call balanceOf on the pool (which is an ERC20 LP token)
const balance = await publicClient.readContract({
address: poolAddress,
abi: ERC20ABI,
functionName: 'balanceOf',
args: [userAddress],
}) as bigint;
setLpBalance(balance);
} catch (err) {
console.error('Error fetching LP token balance:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch LP balance');
setLpBalance(null);
} finally {
setLoading(false);
}
};
fetchLPBalance();
}, [publicClient, mounted, poolAddress, userAddress]);
return {
lpBalance,
loading,
error,
isReady: mounted,
};
}
export function useBurnAmounts(
poolAddress: `0x${string}` | undefined,
lpTokenAmount: bigint | undefined
) {
const publicClient = usePublicClient();
const [mounted, setMounted] = useState(false);
const [burnAmounts, setBurnAmounts] = useState<bigint[] | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
setMounted(true);
}, []);
useEffect(() => {
if (!mounted || !poolAddress || !lpTokenAmount || lpTokenAmount === 0n) {
setBurnAmounts(null);
setLoading(false);
return;
}
const fetchBurnAmounts = async () => {
if (!publicClient) {
setLoading(false);
return;
}
try {
setLoading(true);
setError(null);
// Get chain ID and PartyInfo contract address
const chainId = await publicClient.getChainId();
const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!partyInfoAddress) {
setError('PartyInfo contract not found for current chain');
setBurnAmounts(null);
return;
}
// Call burnAmounts function
const amounts = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`,
abi: IPartyPoolViewerABI,
functionName: 'burnAmounts',
args: [poolAddress, lpTokenAmount],
}) as bigint[];
setBurnAmounts(amounts);
} catch (err) {
console.error('Error fetching burn amounts:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch burn amounts');
setBurnAmounts(null);
} finally {
setLoading(false);
}
};
fetchBurnAmounts();
}, [publicClient, mounted, poolAddress, lpTokenAmount]);
return {
burnAmounts,
loading,
error,
isReady: mounted,
};
}