[wif] slippage for burnSwap

This commit is contained in:
2025-11-26 15:41:48 -04:00
parent 85a7b58d55
commit 99929d8db8
3 changed files with 90 additions and 20 deletions

View File

@@ -151,9 +151,14 @@ export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) {
const { burnSwapAmounts, loading: burnSwapLoading } = useBurnSwapAmounts( const { burnSwapAmounts, loading: burnSwapLoading } = useBurnSwapAmounts(
mode === 'unstake' && !redeemAll ? selectedPool?.address : undefined, mode === 'unstake' && !redeemAll ? selectedPool?.address : undefined,
mode === 'unstake' && !redeemAll ? maxAmountIn : 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) // Fetch burn amounts (for unstake mode when redeeming all)
const { burnAmounts, loading: burnAmountsLoading } = useBurnAmounts( const { burnAmounts, loading: burnAmountsLoading } = useBurnAmounts(
mode === 'unstake' && redeemAll ? selectedPool?.address : undefined, mode === 'unstake' && redeemAll ? selectedPool?.address : undefined,

View File

@@ -8,6 +8,7 @@ import IPartyPoolABI from '@/contracts/IPartyPoolABI';
import IPartyPoolViewerABI from '@/contracts/IPartyPoolViewerABI'; import IPartyPoolViewerABI from '@/contracts/IPartyPoolViewerABI';
import IPartyInfoABI from '@/contracts/IPartyInfoABI'; import IPartyInfoABI from '@/contracts/IPartyInfoABI';
import { ERC20ABI } from '@/contracts/ERC20ABI'; import { ERC20ABI } from '@/contracts/ERC20ABI';
import { calculateSlippage } from './usePartyPool';
// Helper function to format large numbers with K, M, B suffixes // Helper function to format large numbers with K, M, B suffixes
function formatTVL(value: number): string { function formatTVL(value: number): string {
@@ -50,7 +51,7 @@ export function useGetAllTokens(offset: number = 0, limit: number = 100) {
// Get chain ID and contract address // Get chain ID and contract address
const chainId = await publicClient.getChainId(); const chainId = await publicClient.getChainId();
// @ts-ignore // @ts-ignore
const address = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyPoolViewer: string } }>)[chainId.toString()]?.v1?.PartyPlanner; const address = (chainInfo as Record<string, { v1: { PartyPlanner: string } }>)[chainId.toString()]?.v1?.PartyPlanner;
if (!address) { if (!address) {
setError('IPartyPlanner contract not found for current chain'); setError('IPartyPlanner contract not found for current chain');
@@ -465,6 +466,7 @@ export function useGetAllPools(offset: number = 0, limit: number = 100) {
if (isWorking) { if (isWorking) {
// Fetch pool price (use first token as quote, index 0) // Fetch pool price (use first token as quote, index 0)
console.log('fetching pool price')
try { try {
const priceRaw = await publicClient.readContract({ const priceRaw = await publicClient.readContract({
address: partyInfoAddress as `0x${string}`, address: partyInfoAddress as `0x${string}`,
@@ -565,17 +567,20 @@ export interface SwapMintAmounts {
amountInUsed: bigint; amountInUsed: bigint;
fee: bigint; fee: bigint;
lpMinted: bigint; lpMinted: bigint;
calculatedSlippage?: number; // Percentage, e.g. 5.5 means 5.5%
} }
export interface BurnSwapAmounts { export interface BurnSwapAmounts {
amountOut: bigint; amountOut: bigint;
outFee: bigint; outFee: bigint;
calculatedSlippage?: number; // Percentage, e.g. 5.5 means 5.5%
} }
export function useSwapMintAmounts( export function useSwapMintAmounts(
poolAddress: `0x${string}` | undefined, poolAddress: `0x${string}` | undefined,
inputTokenIndex: number | 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 publicClient = usePublicClient();
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -608,26 +613,39 @@ export function useSwapMintAmounts(
// Get chain ID and contract address // Get chain ID and contract address
const chainId = await publicClient.getChainId(); const chainId = await publicClient.getChainId();
// @ts-ignore // @ts-ignore
const viewerAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyPoolViewer: string } }>)[chainId.toString()]?.v1?.PartyPoolViewer; const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!viewerAddress) { if (!partyInfoAddress) {
setError('IPartyPoolViewer contract not found for current chain'); setError('PartyInfo contract not found for current chain');
setSwapMintAmounts(null); setSwapMintAmounts(null);
return; return;
} }
// Call swapMintAmounts function // Call swapMintAmounts function
const result = await publicClient.readContract({ const result = await publicClient.readContract({
address: viewerAddress as `0x${string}`, address: partyInfoAddress as `0x${string}`,
abi: IPartyPoolViewerABI, abi: IPartyPoolViewerABI,
functionName: 'swapMintAmounts', functionName: 'swapMintAmounts',
args: [poolAddress, BigInt(inputTokenIndex), maxAmountIn], args: [poolAddress, BigInt(inputTokenIndex), maxAmountIn],
}) as readonly [bigint, bigint, bigint]; }) 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({ setSwapMintAmounts({
amountInUsed: result[0], amountInUsed: result[0],
fee: result[1], fee: result[1],
lpMinted: result[2], lpMinted: result[2],
calculatedSlippage,
}); });
} catch (err) { } catch (err) {
console.error('Error calling swapMintAmounts:', err); console.error('Error calling swapMintAmounts:', err);
@@ -639,7 +657,7 @@ export function useSwapMintAmounts(
}; };
fetchSwapMintAmounts(); fetchSwapMintAmounts();
}, [publicClient, mounted, poolAddress, inputTokenIndex, maxAmountIn]); }, [publicClient, mounted, poolAddress, inputTokenIndex, maxAmountIn, lpTokenPrice]);
return { return {
swapMintAmounts, swapMintAmounts,
@@ -652,7 +670,9 @@ export function useSwapMintAmounts(
export function useBurnSwapAmounts( export function useBurnSwapAmounts(
poolAddress: `0x${string}` | undefined, poolAddress: `0x${string}` | undefined,
lpAmount: bigint | 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 publicClient = usePublicClient();
const [mounted, setMounted] = useState(false); const [mounted, setMounted] = useState(false);
@@ -681,18 +701,21 @@ export function useBurnSwapAmounts(
try { try {
setLoading(true); setLoading(true);
setError(null); setError(null);
console.log('fetching swap amounts')
// Get chain ID and contract address // Get chain ID and contract address
const chainId = await publicClient.getChainId(); const chainId = await publicClient.getChainId();
// @ts-ignore // @ts-ignore
const viewerAddress = (chainInfo as Record<string, { v1: { PartyPlanner: string; PartyPoolViewer: string } }>)[chainId.toString()]?.v1?.PartyPoolViewer; const partyInfoAddress = (chainInfo as Record<string, { v1: { PartyInfo: string } }>)[chainId.toString()]?.v1?.PartyInfo;
if (!viewerAddress) { if (!partyInfoAddress) {
setError('IPartyPoolViewer contract not found for current chain'); console.log('errores here')
setError('PartyInfo contract not found for current chain');
setBurnSwapAmounts(null); setBurnSwapAmounts(null);
return; return;
} }
console.log('fetching swap amounts 2')
// Log inputs // Log inputs
console.log('🔍 burnSwapAmounts INPUTS:', { console.log('🔍 burnSwapAmounts INPUTS:', {
chainId: chainId.toString(), chainId: chainId.toString(),
@@ -700,12 +723,12 @@ export function useBurnSwapAmounts(
poolAddress, poolAddress,
lpAmount: lpAmount.toString(), lpAmount: lpAmount.toString(),
inputTokenIndex, inputTokenIndex,
viewerAddress, partyInfoAddress,
}); });
// Call burnSwapAmounts function - returns [amountOut, outFee] // Call burnSwapAmounts function - returns [amountOut, outFee]
const result = await publicClient.readContract({ const result = await publicClient.readContract({
address: viewerAddress as `0x${string}`, address: partyInfoAddress as `0x${string}`,
abi: IPartyPoolViewerABI, abi: IPartyPoolViewerABI,
functionName: 'burnSwapAmounts', functionName: 'burnSwapAmounts',
args: [poolAddress, lpAmount, BigInt(inputTokenIndex)], args: [poolAddress, lpAmount, BigInt(inputTokenIndex)],
@@ -717,16 +740,59 @@ export function useBurnSwapAmounts(
amountOut: result[0].toString(), amountOut: result[0].toString(),
outFee: result[1].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 = { const parsedAmounts = {
amountOut: result[0], amountOut: result[0],
outFee: result[1], outFee: result[1],
calculatedSlippage,
}; };
// Log parsed result // Log parsed result
console.log('✅ burnSwapAmounts PARSED:', { console.log('✅ burnSwapAmounts PARSED:', {
amountOut: parsedAmounts.amountOut.toString(), amountOut: parsedAmounts.amountOut.toString(),
outFee: parsedAmounts.outFee.toString(), outFee: parsedAmounts.outFee.toString(),
calculatedSlippage: parsedAmounts.calculatedSlippage,
}); });
setBurnSwapAmounts(parsedAmounts); setBurnSwapAmounts(parsedAmounts);
@@ -740,7 +806,7 @@ export function useBurnSwapAmounts(
}; };
fetchBurnSwapAmounts(); fetchBurnSwapAmounts();
}, [publicClient, mounted, poolAddress, lpAmount, inputTokenIndex]); }, [publicClient, mounted, poolAddress, lpAmount, inputTokenIndex, lpTokenPrice, tokenDecimals]);
return { return {
burnSwapAmounts, burnSwapAmounts,

View File

@@ -28,11 +28,10 @@ export function calculateSlippage(
// Calculate actual swap price with decimal correction // Calculate actual swap price with decimal correction
const swapPrice = Number(swapOutputAmount) / (Number(swapInputAmount) - Number(swapFee)); const swapPrice = Number(swapOutputAmount) / (Number(swapInputAmount) - Number(swapFee));
// Calculate slippage: 1 - (actualPrice / marketPrice) // Calculate slippage percentage: ((swapPrice - marketPrice) / marketPrice) * 100
const slippage = 1 - (swapPrice / marketPrice); const slippage = ((swapPrice - marketPrice) / marketPrice) * 100;
// Convert to percentage return slippage;
return slippage * 100;
} }
export interface SwapAmountResult { export interface SwapAmountResult {