From 99929d8db816ed55f202f9d3f93445451b93678d Mon Sep 17 00:00:00 2001 From: surbhi Date: Wed, 26 Nov 2025 15:41:48 -0400 Subject: [PATCH] [wif] slippage for burnSwap --- src/components/stake-form.tsx | 7 ++- src/hooks/usePartyPlanner.ts | 96 +++++++++++++++++++++++++++++------ src/hooks/usePartyPool.ts | 7 ++- 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/src/components/stake-form.tsx b/src/components/stake-form.tsx index 2170e25..da24bd1 100644 --- a/src/components/stake-form.tsx +++ b/src/components/stake-form.tsx @@ -151,9 +151,14 @@ export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) { const { burnSwapAmounts, loading: burnSwapLoading } = useBurnSwapAmounts( mode === 'unstake' && !redeemAll ? selectedPool?.address : undefined, mode === 'unstake' && !redeemAll ? maxAmountIn : undefined, - mode === 'unstake' && !redeemAll ? inputTokenIndex : undefined + mode === 'unstake' && !redeemAll ? inputTokenIndex : undefined, + undefined, // lpTokenPrice - not needed for burnSwap custom calculation + mode === 'unstake' && !redeemAll && selectedToken ? selectedToken.decimals : undefined ); + + console.log('burn swap maounts', burnSwapAmounts) + // Fetch burn amounts (for unstake mode when redeeming all) const { burnAmounts, loading: burnAmountsLoading } = useBurnAmounts( mode === 'unstake' && redeemAll ? selectedPool?.address : undefined, diff --git a/src/hooks/usePartyPlanner.ts b/src/hooks/usePartyPlanner.ts index 3720c2a..8d6f392 100644 --- a/src/hooks/usePartyPlanner.ts +++ b/src/hooks/usePartyPlanner.ts @@ -8,6 +8,7 @@ import IPartyPoolABI from '@/contracts/IPartyPoolABI'; import IPartyPoolViewerABI from '@/contracts/IPartyPoolViewerABI'; import IPartyInfoABI from '@/contracts/IPartyInfoABI'; import { ERC20ABI } from '@/contracts/ERC20ABI'; +import { calculateSlippage } from './usePartyPool'; // Helper function to format large numbers with K, M, B suffixes function formatTVL(value: number): string { @@ -50,7 +51,7 @@ export function useGetAllTokens(offset: number = 0, limit: number = 100) { // Get chain ID and contract address const chainId = await publicClient.getChainId(); // @ts-ignore - const address = (chainInfo as Record)[chainId.toString()]?.v1?.PartyPlanner; + const address = (chainInfo as Record)[chainId.toString()]?.v1?.PartyPlanner; if (!address) { setError('IPartyPlanner contract not found for current chain'); @@ -465,6 +466,7 @@ export function useGetAllPools(offset: number = 0, limit: number = 100) { if (isWorking) { // Fetch pool price (use first token as quote, index 0) + console.log('fetching pool price') try { const priceRaw = await publicClient.readContract({ address: partyInfoAddress as `0x${string}`, @@ -565,17 +567,20 @@ 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 + maxAmountIn: bigint | undefined, + lpTokenPrice?: number // Market price of the LP token in decimal format ) { const publicClient = usePublicClient(); const [mounted, setMounted] = useState(false); @@ -608,26 +613,39 @@ export function useSwapMintAmounts( // Get chain ID and contract address const chainId = await publicClient.getChainId(); // @ts-ignore - const viewerAddress = (chainInfo as Record)[chainId.toString()]?.v1?.PartyPoolViewer; + const partyInfoAddress = (chainInfo as Record)[chainId.toString()]?.v1?.PartyInfo; - if (!viewerAddress) { - setError('IPartyPoolViewer contract not found for current chain'); + if (!partyInfoAddress) { + setError('PartyInfo contract not found for current chain'); setSwapMintAmounts(null); return; } // Call swapMintAmounts function const result = await publicClient.readContract({ - address: viewerAddress as `0x${string}`, + address: partyInfoAddress as `0x${string}`, abi: IPartyPoolViewerABI, functionName: 'swapMintAmounts', args: [poolAddress, BigInt(inputTokenIndex), maxAmountIn], }) as readonly [bigint, bigint, bigint]; + // Calculate slippage if LP token price is provided + let calculatedSlippage: number | undefined; + if (lpTokenPrice !== undefined) { + try { + // For swapMint: output is result[0] (amountInUsed), input is maxAmountIn, fee is result[2] + calculatedSlippage = calculateSlippage(lpTokenPrice, result[0], maxAmountIn, result[2]); + console.log('swapMint calculatedSlippage', calculatedSlippage); + } catch (slippageErr) { + console.error(`Error calculating slippage for swapMint:`, slippageErr); + } + } + setSwapMintAmounts({ amountInUsed: result[0], fee: result[1], lpMinted: result[2], + calculatedSlippage, }); } catch (err) { console.error('Error calling swapMintAmounts:', err); @@ -639,7 +657,7 @@ export function useSwapMintAmounts( }; fetchSwapMintAmounts(); - }, [publicClient, mounted, poolAddress, inputTokenIndex, maxAmountIn]); + }, [publicClient, mounted, poolAddress, inputTokenIndex, maxAmountIn, lpTokenPrice]); return { swapMintAmounts, @@ -652,7 +670,9 @@ export function useSwapMintAmounts( export function useBurnSwapAmounts( poolAddress: `0x${string}` | undefined, lpAmount: bigint | undefined, - inputTokenIndex: number | undefined + inputTokenIndex: number | undefined, + lpTokenPrice?: number, // Market price of the LP token in decimal format + tokenDecimals?: number // Decimals of the output token ) { const publicClient = usePublicClient(); const [mounted, setMounted] = useState(false); @@ -681,18 +701,21 @@ export function useBurnSwapAmounts( try { setLoading(true); setError(null); - + console.log('fetching swap amounts') // Get chain ID and contract address const chainId = await publicClient.getChainId(); // @ts-ignore - const viewerAddress = (chainInfo as Record)[chainId.toString()]?.v1?.PartyPoolViewer; + const partyInfoAddress = (chainInfo as Record)[chainId.toString()]?.v1?.PartyInfo; - if (!viewerAddress) { - setError('IPartyPoolViewer contract not found for current chain'); + if (!partyInfoAddress) { + console.log('errores here') + setError('PartyInfo contract not found for current chain'); setBurnSwapAmounts(null); return; } + console.log('fetching swap amounts 2') + // Log inputs console.log('🔍 burnSwapAmounts INPUTS:', { chainId: chainId.toString(), @@ -700,12 +723,12 @@ export function useBurnSwapAmounts( poolAddress, lpAmount: lpAmount.toString(), inputTokenIndex, - viewerAddress, + partyInfoAddress, }); // Call burnSwapAmounts function - returns [amountOut, outFee] const result = await publicClient.readContract({ - address: viewerAddress as `0x${string}`, + address: partyInfoAddress as `0x${string}`, abi: IPartyPoolViewerABI, functionName: 'burnSwapAmounts', args: [poolAddress, lpAmount, BigInt(inputTokenIndex)], @@ -717,16 +740,59 @@ export function useBurnSwapAmounts( amountOut: result[0].toString(), outFee: result[1].toString(), }); + // 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) + const marketPrice = Number(poolPriceInt128) / 2 ** 64; + + // 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; + + // Calculate slippage percentage: ((swapPrice - marketPrice) / marketPrice) * 100 + calculatedSlippage = ((swapPrice - marketPrice) / marketPrice) * 100; + + console.log('burnSwap slippage calculation:', { + marketPrice, + 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, }; // Log parsed result console.log('✅ burnSwapAmounts PARSED:', { amountOut: parsedAmounts.amountOut.toString(), outFee: parsedAmounts.outFee.toString(), + calculatedSlippage: parsedAmounts.calculatedSlippage, }); setBurnSwapAmounts(parsedAmounts); @@ -740,7 +806,7 @@ export function useBurnSwapAmounts( }; fetchBurnSwapAmounts(); - }, [publicClient, mounted, poolAddress, lpAmount, inputTokenIndex]); + }, [publicClient, mounted, poolAddress, lpAmount, inputTokenIndex, lpTokenPrice, tokenDecimals]); return { burnSwapAmounts, diff --git a/src/hooks/usePartyPool.ts b/src/hooks/usePartyPool.ts index 9e56906..696d222 100644 --- a/src/hooks/usePartyPool.ts +++ b/src/hooks/usePartyPool.ts @@ -28,11 +28,10 @@ export function calculateSlippage( // Calculate actual swap price with decimal correction const swapPrice = Number(swapOutputAmount) / (Number(swapInputAmount) - Number(swapFee)); - // Calculate slippage: 1 - (actualPrice / marketPrice) - const slippage = 1 - (swapPrice / marketPrice); + // Calculate slippage percentage: ((swapPrice - marketPrice) / marketPrice) * 100 + const slippage = ((swapPrice - marketPrice) / marketPrice) * 100; - // Convert to percentage - return slippage * 100; + return slippage; } export interface SwapAmountResult {