)}
+ {/* Redeem All Tokens Display */}
+ {mode === 'unstake' && redeemAll && poolTokens.length > 0 && (
+
@@ -536,12 +670,14 @@ export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) {
- {mode === 'stake' ? 'Approving Stake' : 'Approving Unstake'}
+ {mode === 'stake' ? 'Approving Stake' : redeemAll ? 'Approving Redeem All' : 'Approving Unstake'}
{mode === 'stake'
? `Staking ${stakeAmount} ${selectedToken?.symbol} to ${selectedPool?.symbol}`
- : `Unstaking ${stakeAmount} ${selectedPool?.symbol} LP for ${selectedToken?.symbol}`
+ : redeemAll
+ ? `Redeeming ${stakeAmount} ${selectedPool?.symbol} LP for all pool tokens`
+ : `Unstaking ${stakeAmount} ${selectedPool?.symbol} LP for ${selectedToken?.symbol}`
}
@@ -554,7 +690,7 @@ export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) {
- {mode === 'stake' ? 'Stake Confirmed!' : 'Unstake Confirmed!'}
+ {mode === 'stake' ? 'Stake Confirmed!' : redeemAll ? 'Redeem Confirmed!' : 'Unstake Confirmed!'}
{/* Display actual amounts or estimates */}
@@ -594,6 +730,44 @@ export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) {
>
)}
+ ) : redeemAll ? (
+ // Redeem All mode success message
+
+ {actualBurnAmounts && selectedPool ? (
+ // Show actual amounts from transaction
+ <>
+
+ LP Burned:
+ {formatUnits(actualBurnAmounts.lpBurned, 18)} {selectedPool.symbol}
+
+
Tokens Received:
+ {actualBurnAmounts.withdrawAmounts.map((amount, index) => {
+ const token = poolTokens[index];
+ if (!token) return null;
+
+ return (
+
+ {token.symbol}:
+
+ {formatUnits(amount, token.decimals)}
+
+
+ );
+ })}
+ >
+ ) : (
+ // Fallback to estimates
+ <>
+
+ Successfully redeemed {stakeAmount} {selectedPool?.symbol} LP for all pool tokens
+
+
+ *Disclaimer: This is an estimate from the protocol. The actual amounts might be slightly different due to slippage.
+
+
+ >
+ )}
+
) : (
// Unstake mode success message
diff --git a/src/components/unstake-basket-form.tsx b/src/components/unstake-basket-form.tsx
deleted file mode 100644
index 9ad6531..0000000
--- a/src/components/unstake-basket-form.tsx
+++ /dev/null
@@ -1,379 +0,0 @@
-'use client';
-
-import { useState, useEffect, useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
-import { Input } from '@/components/ui/input';
-import { Button } from '@/components/ui/button';
-import { CheckCircle, XCircle, Loader2, Trash2 } from 'lucide-react';
-import { useAccount, usePublicClient } from 'wagmi';
-import { useGetAllPools, useLPTokenBalance, type PoolDetails } from '@/hooks/usePartyPlanner';
-import { useBurn, type ActualBurnAmounts } from '@/hooks/usePartyPool';
-import { formatUnits, parseUnits } from 'viem';
-import IPartyPoolABI from '@/contracts/IPartyPoolABI';
-import { ERC20ABI } from '@/contracts/ERC20ABI';
-
-type TransactionStatus = 'idle' | 'pending' | 'success' | 'error';
-
-interface PoolWithBalance extends PoolDetails {
- lpBalance: bigint;
-}
-
-interface TokenInfo {
- address: `0x${string}`;
- symbol: string;
- decimals: number;
-}
-
-export function UnstakeBasketForm() {
- const { t } = useTranslation();
- const { isConnected, address } = useAccount();
- const publicClient = usePublicClient();
- const [selectedPools, setSelectedPools] = useState
>(new Set());
- const [poolsWithBalances, setPoolsWithBalances] = useState([]);
- const [transactionStatus, setTransactionStatus] = useState('idle');
- const [transactionError, setTransactionError] = useState(null);
- const [actualBurnResults, setActualBurnResults] = useState<{[key: string]: ActualBurnAmounts}>({});
- const [poolTokens, setPoolTokens] = useState<{[key: string]: TokenInfo[]}>({});
-
- // Fetch all pools using the hook
- const { poolDetails, loading: poolsLoading } = useGetAllPools();
-
- // Initialize burn hook
- const { executeBurn, isBurning } = useBurn();
-
- // Fetch LP balances for all pools
- useEffect(() => {
- if (!poolDetails || !address || !publicClient) return;
-
- const fetchBalances = async () => {
- const poolsWithBal: PoolWithBalance[] = [];
-
- for (const pool of poolDetails) {
- try {
- const balance = await publicClient.readContract({
- address: pool.address,
- abi: IPartyPoolABI,
- functionName: 'balanceOf',
- args: [address],
- }) as bigint;
-
- if (balance > 0n) {
- poolsWithBal.push({
- ...pool,
- lpBalance: balance,
- });
- }
- } catch (err) {
- console.error(`Error fetching balance for pool ${pool.address}:`, err);
- }
- }
-
- setPoolsWithBalances(poolsWithBal);
- };
-
- fetchBalances();
- }, [poolDetails, address, publicClient]);
-
- // Fetch token details for selected pools
- useEffect(() => {
- if (!publicClient || selectedPools.size === 0) return;
-
- const fetchTokenDetails = async () => {
- const tokenInfoMap: {[key: string]: TokenInfo[]} = {};
-
- for (const poolAddress of Array.from(selectedPools)) {
- const pool = poolsWithBalances.find(p => p.address === poolAddress);
- if (!pool) continue;
-
- const tokenInfos: TokenInfo[] = [];
-
- for (const tokenAddress of pool.tokens) {
- try {
- const [symbol, decimals] = await Promise.all([
- publicClient.readContract({
- address: tokenAddress as `0x${string}`,
- abi: ERC20ABI,
- functionName: 'symbol',
- }) as Promise,
- publicClient.readContract({
- address: tokenAddress as `0x${string}`,
- abi: ERC20ABI,
- functionName: 'decimals',
- }) as Promise,
- ]);
-
- tokenInfos.push({
- address: tokenAddress as `0x${string}`,
- symbol,
- decimals,
- });
- } catch (err) {
- console.error(`Error fetching token details for ${tokenAddress}:`, err);
- }
- }
-
- tokenInfoMap[poolAddress] = tokenInfos;
- }
-
- setPoolTokens(tokenInfoMap);
- };
-
- fetchTokenDetails();
- }, [publicClient, selectedPools, poolsWithBalances]);
-
- const togglePoolSelection = (poolAddress: string) => {
- const newSelected = new Set(selectedPools);
- if (newSelected.has(poolAddress)) {
- newSelected.delete(poolAddress);
- } else {
- newSelected.add(poolAddress);
- }
- setSelectedPools(newSelected);
- };
-
- const handleBurnAll = async () => {
- if (selectedPools.size === 0) {
- return;
- }
-
- setTransactionStatus('pending');
- setTransactionError(null);
- setActualBurnResults({});
-
- try {
- const results: {[key: string]: ActualBurnAmounts} = {};
-
- // Execute burn for each selected pool
- for (const poolAddress of Array.from(selectedPools)) {
- const pool = poolsWithBalances.find(p => p.address === poolAddress);
- if (!pool) continue;
-
- console.log(`Burning LP tokens for pool ${pool.symbol}...`);
-
- // Execute the burn transaction
- const result = await executeBurn(
- pool.address,
- pool.lpBalance,
- false // unwrap = false by default
- );
-
- // Store actual burn amounts if available
- if (result?.actualBurnAmounts) {
- results[poolAddress] = result.actualBurnAmounts;
- }
- }
-
- setActualBurnResults(results);
- setTransactionStatus('success');
- } catch (err) {
- console.error('Burn failed:', err);
- setTransactionError(err instanceof Error ? err.message : 'Transaction failed');
- setTransactionStatus('error');
- }
- };
-
- const handleCloseModal = () => {
- if (transactionStatus === 'success') {
- // Clear selections and refresh
- setSelectedPools(new Set());
- // Refresh pool balances
- window.location.reload();
- }
- setTransactionStatus('idle');
- setTransactionError(null);
- };
-
- return (
-
-
- Unstake Basket
-
- Select pools to burn all LP tokens and receive all underlying tokens proportionally
-
-
-
- {/* Pool Selection List */}
- {poolsLoading ? (
-
-
-
- ) : poolsWithBalances.length === 0 ? (
-
-
No pools with LP token balance found.
-
Stake some tokens first to use this feature.
-
- ) : (
-
- {poolsWithBalances.map((pool) => (
-
togglePoolSelection(pool.address)}
- >
-
-
-
-
{}}
- className="w-4 h-4"
- />
-
-
{pool.symbol}
-
{pool.name}
-
-
-
-
-
- {formatUnits(pool.lpBalance, 18)} LP
-
- {poolTokens[pool.address] && (
-
- {poolTokens[pool.address].length} tokens
-
- )}
-
-
- {selectedPools.has(pool.address) && poolTokens[pool.address] && (
-
-
You will receive:
-
- {poolTokens[pool.address].map((token) => (
-
- {token.symbol}
-
- (proportional to pool composition)
-
-
- ))}
-
-
- )}
-
- ))}
-
- )}
-
- {/* Burn Button */}
-
- {!isConnected
- ? 'Connect Wallet'
- : isBurning
- ? 'Burning...'
- : `Burn ${selectedPools.size} Pool${selectedPools.size !== 1 ? 's' : ''}`}
-
-
- {selectedPools.size > 0 && (
-
- This will burn all LP tokens from {selectedPools.size} selected pool{selectedPools.size !== 1 ? 's' : ''}
-
- )}
-
-
- {/* Transaction Modal Overlay */}
- {transactionStatus !== 'idle' && (
-
-
- {transactionStatus === 'pending' && (
-
-
-
- Burning LP Tokens
-
-
- Burning LP tokens from {selectedPools.size} pool{selectedPools.size !== 1 ? 's' : ''}
-
-
- Please confirm the transactions in your wallet
-
-
- )}
-
- {transactionStatus === 'success' && (
-
-
-
- Burn Confirmed!
-
-
-
- {Object.entries(actualBurnResults).map(([poolAddress, burnAmounts]) => {
- const pool = poolsWithBalances.find(p => p.address === poolAddress);
- const tokens = poolTokens[poolAddress];
-
- if (!pool || !tokens) return null;
-
- return (
-
-
{pool.symbol}
-
-
- LP Burned:
-
- {formatUnits(burnAmounts.lpBurned, 18)} {pool.symbol}
-
-
-
Tokens Received:
- {burnAmounts.withdrawAmounts.map((amount, index) => {
- const token = tokens[index];
- if (!token) return null;
-
- return (
-
- {token.symbol}:
-
- {formatUnits(amount, token.decimals)}
-
-
- );
- })}
-
-
- );
- })}
-
-
-
- Close
-
-
- )}
-
- {transactionStatus === 'error' && (
-
-
-
- Burn Failed
-
-
- {transactionError || 'Transaction failed'}
-
-
- Close
-
-
- )}
-
-
- )}
-
- );
-}
\ No newline at end of file