burn swap and page menu updates
This commit is contained in:
@@ -5,18 +5,24 @@ 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 { ChevronDown, CheckCircle, XCircle, Loader2 } from 'lucide-react';
|
||||
import { ChevronDown, CheckCircle, XCircle, Loader2, ArrowDownUp } from 'lucide-react';
|
||||
import { useAccount } from 'wagmi';
|
||||
import { useGetAllPools, useTokenDetails, useSwapMintAmounts, type PoolDetails, type TokenDetails } from '@/hooks/usePartyPlanner';
|
||||
import { useSwapMint } from '@/hooks/usePartyPool';
|
||||
import { useGetAllPools, useTokenDetails, useSwapMintAmounts, useBurnSwapAmounts, useLPTokenBalance, type PoolDetails, type TokenDetails } from '@/hooks/usePartyPlanner';
|
||||
import { useSwapMint, useBurnSwap } from '@/hooks/usePartyPool';
|
||||
import { formatUnits, parseUnits } from 'viem';
|
||||
import IPartyPoolABI from '@/contracts/IPartyPoolABI';
|
||||
|
||||
type TransactionStatus = 'idle' | 'pending' | 'success' | 'error';
|
||||
type Mode = 'stake' | 'unstake';
|
||||
|
||||
export function StakeForm() {
|
||||
interface StakeFormProps {
|
||||
defaultMode?: Mode;
|
||||
}
|
||||
|
||||
export function StakeForm({ defaultMode = 'stake' }: StakeFormProps) {
|
||||
const { t } = useTranslation();
|
||||
const { isConnected, address } = useAccount();
|
||||
const [mode, setMode] = useState<Mode>(defaultMode);
|
||||
const [stakeAmount, setStakeAmount] = useState('');
|
||||
const [selectedPool, setSelectedPool] = useState<PoolDetails | null>(null);
|
||||
const [selectedToken, setSelectedToken] = useState<TokenDetails | null>(null);
|
||||
@@ -33,10 +39,17 @@ export function StakeForm() {
|
||||
// Get token details for the user
|
||||
const { tokenDetails, loading: tokensLoading } = useTokenDetails(address);
|
||||
|
||||
// Initialize swap mint hook
|
||||
// Initialize swap mint and burn swap hooks
|
||||
const { executeSwapMint, isSwapMinting } = useSwapMint();
|
||||
const { executeBurnSwap, isBurnSwapping } = useBurnSwap();
|
||||
|
||||
// Get available tokens for staking based on selected pool
|
||||
// Fetch LP token balance (for unstake mode) - must be before isAmountExceedingBalance
|
||||
const { lpBalance } = useLPTokenBalance(
|
||||
mode === 'unstake' ? selectedPool?.address : undefined,
|
||||
address
|
||||
);
|
||||
|
||||
// Get available tokens for staking based on selected pool (for unstake mode)
|
||||
const availableTokensForPool = selectedPool && tokenDetails
|
||||
? tokenDetails.filter(token =>
|
||||
selectedPool.tokens.some(poolToken =>
|
||||
@@ -45,18 +58,35 @@ export function StakeForm() {
|
||||
)
|
||||
: [];
|
||||
|
||||
// Get available pools for staking based on selected token (for stake mode)
|
||||
const availablePoolsForToken = selectedToken && poolDetails
|
||||
? poolDetails.filter(pool =>
|
||||
pool.tokens.some(poolToken =>
|
||||
poolToken.toLowerCase() === selectedToken.address.toLowerCase()
|
||||
)
|
||||
)
|
||||
: [];
|
||||
|
||||
// Check if amount exceeds balance
|
||||
const isAmountExceedingBalance = useMemo(() => {
|
||||
if (!stakeAmount || !selectedToken) return false;
|
||||
if (!stakeAmount) return false;
|
||||
|
||||
try {
|
||||
const amountInWei = parseUnits(stakeAmount, selectedToken.decimals);
|
||||
return amountInWei > selectedToken.balance;
|
||||
if (mode === 'stake') {
|
||||
if (!selectedToken) return false;
|
||||
const amountInWei = parseUnits(stakeAmount, selectedToken.decimals);
|
||||
return amountInWei > selectedToken.balance;
|
||||
} else {
|
||||
// Unstake mode - check against LP balance
|
||||
if (!lpBalance) return false;
|
||||
const amountInWei = parseUnits(stakeAmount, 18); // LP tokens have 18 decimals
|
||||
return amountInWei > lpBalance;
|
||||
}
|
||||
} catch {
|
||||
// If parseUnits fails (invalid input), don't show error
|
||||
return false;
|
||||
}
|
||||
}, [stakeAmount, selectedToken]);
|
||||
}, [stakeAmount, selectedToken, mode, lpBalance]);
|
||||
|
||||
// Get the input token index in the selected pool
|
||||
const inputTokenIndex = useMemo(() => {
|
||||
@@ -74,17 +104,26 @@ export function StakeForm() {
|
||||
if (!stakeAmount || !selectedToken) return undefined;
|
||||
|
||||
try {
|
||||
return parseUnits(stakeAmount, selectedToken.decimals);
|
||||
// For unstake mode, LP tokens always have 18 decimals
|
||||
const decimals = mode === 'unstake' ? 18 : selectedToken.decimals;
|
||||
return parseUnits(stakeAmount, decimals);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}, [stakeAmount, selectedToken]);
|
||||
}, [stakeAmount, selectedToken, mode]);
|
||||
|
||||
// Fetch swap mint amounts
|
||||
// Fetch swap mint amounts (for stake mode)
|
||||
const { swapMintAmounts, loading: swapMintLoading } = useSwapMintAmounts(
|
||||
selectedPool?.address,
|
||||
inputTokenIndex,
|
||||
maxAmountIn
|
||||
mode === 'stake' ? selectedPool?.address : undefined,
|
||||
mode === 'stake' ? inputTokenIndex : undefined,
|
||||
mode === 'stake' ? maxAmountIn : undefined
|
||||
);
|
||||
|
||||
// Fetch burn swap amounts (for unstake mode)
|
||||
const { burnSwapAmounts, loading: burnSwapLoading } = useBurnSwapAmounts(
|
||||
mode === 'unstake' ? selectedPool?.address : undefined,
|
||||
mode === 'unstake' ? maxAmountIn : undefined,
|
||||
mode === 'unstake' ? inputTokenIndex : undefined
|
||||
);
|
||||
|
||||
// Close dropdowns when clicking outside
|
||||
@@ -112,17 +151,27 @@ export function StakeForm() {
|
||||
setTransactionError(null);
|
||||
|
||||
try {
|
||||
// Execute the swap mint transaction
|
||||
await executeSwapMint(
|
||||
selectedPool.address,
|
||||
selectedToken.address,
|
||||
inputTokenIndex,
|
||||
maxAmountIn
|
||||
);
|
||||
if (mode === 'stake') {
|
||||
// Execute the swap mint transaction
|
||||
await executeSwapMint(
|
||||
selectedPool.address,
|
||||
selectedToken.address,
|
||||
inputTokenIndex,
|
||||
maxAmountIn
|
||||
);
|
||||
} else {
|
||||
// Execute the burn swap transaction
|
||||
await executeBurnSwap(
|
||||
selectedPool.address,
|
||||
maxAmountIn,
|
||||
inputTokenIndex,
|
||||
false // unwrap = false by default
|
||||
);
|
||||
}
|
||||
|
||||
setTransactionStatus('success');
|
||||
} catch (err) {
|
||||
console.error('Stake failed:', err);
|
||||
console.error(`${mode === 'stake' ? 'Stake' : 'Unstake'} failed:`, err);
|
||||
setTransactionError(err instanceof Error ? err.message : 'Transaction failed');
|
||||
setTransactionStatus('error');
|
||||
}
|
||||
@@ -139,120 +188,262 @@ export function StakeForm() {
|
||||
setTransactionError(null);
|
||||
};
|
||||
|
||||
const toggleMode = () => {
|
||||
setMode(mode === 'stake' ? 'unstake' : 'stake');
|
||||
// Clear selections when switching modes
|
||||
setStakeAmount('');
|
||||
setSelectedPool(null);
|
||||
setSelectedToken(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="w-full max-w-md mx-auto relative">
|
||||
<CardHeader>
|
||||
<div className="flex justify-between items-center">
|
||||
<CardTitle>Stake</CardTitle>
|
||||
<CardTitle>{mode === 'stake' ? 'Stake' : 'Unstake'}</CardTitle>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Pool Selection */}
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectPool')}</label>
|
||||
</div>
|
||||
<div className="relative" ref={poolDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsPoolDropdownOpen(!isPoolDropdownOpen)}
|
||||
>
|
||||
{selectedPool ? (
|
||||
<div className="flex flex-col items-start">
|
||||
<span className="font-medium">{selectedPool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{selectedPool.name}</span>
|
||||
</div>
|
||||
) : (
|
||||
t('stake.selectPool')
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
{isPoolDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{poolDetails && poolDetails.length > 0 ? (
|
||||
poolDetails.map((pool) => (
|
||||
<button
|
||||
key={pool.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedPool(pool);
|
||||
setIsPoolDropdownOpen(false);
|
||||
// Reset token selection when pool changes
|
||||
setSelectedToken(null);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{pool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{pool.name}</span>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{poolsLoading ? 'Loading pools...' : 'No pools available'}
|
||||
{/* First Selection - depends on mode */}
|
||||
{mode === 'stake' ? (
|
||||
/* Pool Selection (Stake Mode) */
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectPool')}</label>
|
||||
</div>
|
||||
<div className="relative" ref={poolDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsPoolDropdownOpen(!isPoolDropdownOpen)}
|
||||
>
|
||||
{selectedPool ? (
|
||||
<div className="flex flex-col items-start">
|
||||
<span className="font-medium">{selectedPool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{selectedPool.name}</span>
|
||||
</div>
|
||||
) : (
|
||||
t('stake.selectPool')
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
{isPoolDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{poolDetails && poolDetails.length > 0 ? (
|
||||
poolDetails.map((pool) => (
|
||||
<button
|
||||
key={pool.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedPool(pool);
|
||||
setIsPoolDropdownOpen(false);
|
||||
setSelectedToken(null);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{pool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{pool.name}</span>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{poolsLoading ? 'Loading pools...' : 'No pools available'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Pool Selection (Unstake Mode) */
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectPool')}</label>
|
||||
</div>
|
||||
<div className="relative" ref={poolDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsPoolDropdownOpen(!isPoolDropdownOpen)}
|
||||
>
|
||||
{selectedPool ? (
|
||||
<div className="flex flex-col items-start">
|
||||
<span className="font-medium">{selectedPool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{selectedPool.name}</span>
|
||||
</div>
|
||||
) : (
|
||||
t('stake.selectPool')
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
{isPoolDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{poolDetails && poolDetails.length > 0 ? (
|
||||
poolDetails.map((pool) => (
|
||||
<button
|
||||
key={pool.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedPool(pool);
|
||||
setIsPoolDropdownOpen(false);
|
||||
setSelectedToken(null);
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{pool.symbol}</span>
|
||||
<span className="text-xs text-muted-foreground">{pool.name}</span>
|
||||
</div>
|
||||
</button>
|
||||
))
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{poolsLoading ? 'Loading pools...' : 'No pools available'}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Toggle Button */}
|
||||
<div className="flex justify-center">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={toggleMode}
|
||||
className="rounded-full"
|
||||
title={mode === 'stake' ? 'Switch to Unstake' : 'Switch to Stake'}
|
||||
>
|
||||
<ArrowDownUp className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Token Selection */}
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectToken')}</label>
|
||||
</div>
|
||||
<div className="relative" ref={tokenDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsTokenDropdownOpen(!isTokenDropdownOpen)}
|
||||
disabled={!selectedPool}
|
||||
>
|
||||
{selectedToken ? (
|
||||
<span className="font-medium">{selectedToken.symbol}</span>
|
||||
) : (
|
||||
t('stake.selectToken')
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
<div className="text-xs text-muted-foreground text-right mt-1">
|
||||
{t('swap.balance')}: {selectedToken ? formatUnits(selectedToken.balance, selectedToken.decimals) : '0.00'}
|
||||
{/* Second Selection - depends on mode */}
|
||||
{mode === 'stake' ? (
|
||||
/* Token Selection (Stake Mode) */
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectToken')}</label>
|
||||
</div>
|
||||
{isTokenDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{availableTokensForPool.length > 0 ? (
|
||||
availableTokensForPool.map((token) => (
|
||||
<button
|
||||
key={token.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedToken(token);
|
||||
setIsTokenDropdownOpen(false);
|
||||
}}
|
||||
>
|
||||
<span className="font-medium">{token.symbol}</span>
|
||||
</button>
|
||||
))
|
||||
) : selectedPool ? (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{tokensLoading ? 'Loading tokens...' : 'No tokens available for this pool'}
|
||||
</div>
|
||||
<div className="relative" ref={tokenDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsTokenDropdownOpen(!isTokenDropdownOpen)}
|
||||
disabled={!selectedPool}
|
||||
>
|
||||
{selectedToken ? (
|
||||
<span className="font-medium">{selectedToken.symbol}</span>
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
Select a pool first
|
||||
</div>
|
||||
t('stake.selectToken')
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
<div className="text-xs text-muted-foreground text-right mt-1">
|
||||
{t('swap.balance')}: {selectedToken ? formatUnits(selectedToken.balance, selectedToken.decimals) : '0.00'}
|
||||
</div>
|
||||
)}
|
||||
{isTokenDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{availableTokensForPool.length > 0 ? (
|
||||
availableTokensForPool.map((token) => (
|
||||
<button
|
||||
key={token.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedToken(token);
|
||||
setIsTokenDropdownOpen(false);
|
||||
}}
|
||||
>
|
||||
<span className="font-medium">{token.symbol}</span>
|
||||
</button>
|
||||
))
|
||||
) : selectedPool ? (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{tokensLoading ? 'Loading tokens...' : 'No tokens available for this pool'}
|
||||
</div>
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
Select a pool first
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
/* Token Selection (Unstake Mode) */
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.selectToken')}</label>
|
||||
</div>
|
||||
<div className="relative" ref={tokenDropdownRef}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
className="w-full h-16 justify-between"
|
||||
onClick={() => setIsTokenDropdownOpen(!isTokenDropdownOpen)}
|
||||
disabled={!selectedPool}
|
||||
>
|
||||
{selectedToken ? (
|
||||
<span className="font-medium">{selectedToken.symbol}</span>
|
||||
) : (
|
||||
t('stake.selectToken')
|
||||
)}
|
||||
<ChevronDown className="h-4 w-4 ml-2" />
|
||||
</Button>
|
||||
<div className="text-xs text-muted-foreground text-right mt-1">
|
||||
{t('swap.balance')}: {lpBalance !== null && selectedPool ? formatUnits(lpBalance, 18) : '0.00'} {selectedPool?.symbol || 'LP'}
|
||||
</div>
|
||||
{isTokenDropdownOpen && (
|
||||
<div className="absolute z-50 w-full mt-2 bg-popover border rounded-md shadow-lg max-h-[300px] overflow-y-auto">
|
||||
{availableTokensForPool.length > 0 ? (
|
||||
availableTokensForPool.map((token) => (
|
||||
<button
|
||||
key={token.address}
|
||||
className="w-full px-4 py-3 text-left hover:bg-accent focus:bg-accent focus:outline-none"
|
||||
onClick={() => {
|
||||
setSelectedToken(token);
|
||||
setIsTokenDropdownOpen(false);
|
||||
}}
|
||||
>
|
||||
<span className="font-medium">{token.symbol}</span>
|
||||
</button>
|
||||
))
|
||||
) : selectedPool ? (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
{tokensLoading ? 'Loading tokens...' : 'No tokens available for this pool'}
|
||||
</div>
|
||||
) : (
|
||||
<div className="px-4 py-3 text-sm text-muted-foreground">
|
||||
Select a pool first
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Amount Input */}
|
||||
<div className="space-y-2">
|
||||
<div className="text-sm">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<label className="text-muted-foreground">{t('stake.amount')}</label>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 px-2 text-xs"
|
||||
onClick={() => {
|
||||
if (mode === 'stake' && selectedToken) {
|
||||
setStakeAmount(formatUnits(selectedToken.balance, selectedToken.decimals));
|
||||
} else if (mode === 'unstake' && lpBalance !== null) {
|
||||
setStakeAmount(formatUnits(lpBalance, 18));
|
||||
}
|
||||
}}
|
||||
disabled={!selectedToken || !selectedPool || (mode === 'stake' ? !selectedToken : lpBalance === null)}
|
||||
>
|
||||
MAX
|
||||
</Button>
|
||||
</div>
|
||||
<Input
|
||||
type="number"
|
||||
@@ -269,8 +460,8 @@ export function StakeForm() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Swap Mint Amounts Display */}
|
||||
{swapMintAmounts && selectedToken && !isAmountExceedingBalance && (
|
||||
{/* Swap Mint Amounts Display (Stake Mode) */}
|
||||
{mode === 'stake' && swapMintAmounts && selectedToken && !isAmountExceedingBalance && (
|
||||
<div className="px-4 py-3 bg-muted/30 rounded-lg space-y-2">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-muted-foreground">{t('stake.amountUsed')}:</span>
|
||||
@@ -293,17 +484,29 @@ export function StakeForm() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stake Button */}
|
||||
{/* Burn Swap Amounts Display (Unstake Mode) */}
|
||||
{mode === 'unstake' && burnSwapAmounts && selectedToken && !isAmountExceedingBalance && (
|
||||
<div className="px-4 py-3 bg-muted/30 rounded-lg space-y-2">
|
||||
<div className="flex justify-between text-sm">
|
||||
<span className="text-muted-foreground">{t('stake.amountOut')}:</span>
|
||||
<span className="font-medium">
|
||||
{burnSwapLoading ? 'Calculating...' : `${formatUnits(burnSwapAmounts, selectedToken.decimals)} ${selectedToken.symbol}`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Stake/Unstake Button */}
|
||||
<Button
|
||||
className="w-full h-14 text-lg"
|
||||
onClick={handleStake}
|
||||
disabled={!isConnected || !stakeAmount || !selectedPool || !selectedToken || isAmountExceedingBalance || isSwapMinting}
|
||||
disabled={!isConnected || !stakeAmount || !selectedPool || !selectedToken || isAmountExceedingBalance || isSwapMinting || isBurnSwapping}
|
||||
>
|
||||
{!isConnected
|
||||
? t('swap.connectWalletToSwap')
|
||||
: isSwapMinting
|
||||
? 'Staking...'
|
||||
: t('stake.stakeButton')}
|
||||
: (isSwapMinting || isBurnSwapping)
|
||||
? mode === 'stake' ? 'Staking...' : 'Unstaking...'
|
||||
: mode === 'stake' ? t('stake.stakeButton') : 'Unstake'}
|
||||
</Button>
|
||||
</CardContent>
|
||||
|
||||
@@ -314,9 +517,14 @@ export function StakeForm() {
|
||||
{transactionStatus === 'pending' && (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<Loader2 className="h-16 w-16 animate-spin text-primary" />
|
||||
<h3 className="text-xl font-semibold text-center">Approving Stake</h3>
|
||||
<h3 className="text-xl font-semibold text-center">
|
||||
{mode === 'stake' ? 'Approving Stake' : 'Approving Unstake'}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground text-center">
|
||||
Staking {stakeAmount} {selectedToken?.symbol} to {selectedPool?.symbol}
|
||||
{mode === 'stake'
|
||||
? `Staking ${stakeAmount} ${selectedToken?.symbol} to ${selectedPool?.symbol}`
|
||||
: `Unstaking ${stakeAmount} ${selectedPool?.symbol} LP for ${selectedToken?.symbol}`
|
||||
}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground text-center">
|
||||
Please confirm the transactions in your wallet
|
||||
@@ -327,9 +535,14 @@ export function StakeForm() {
|
||||
{transactionStatus === 'success' && (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<CheckCircle className="h-16 w-16 text-green-500" />
|
||||
<h3 className="text-xl font-semibold text-center">Stake Confirmed!</h3>
|
||||
<h3 className="text-xl font-semibold text-center">
|
||||
{mode === 'stake' ? 'Stake Confirmed!' : 'Unstake Confirmed!'}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground text-center">
|
||||
Successfully staked {stakeAmount} {selectedToken?.symbol} to {selectedPool?.symbol}
|
||||
{mode === 'stake'
|
||||
? `Successfully staked ${stakeAmount} ${selectedToken?.symbol} to ${selectedPool?.symbol}`
|
||||
: `Successfully unstaked ${stakeAmount} ${selectedPool?.symbol} LP for ${selectedToken?.symbol}`
|
||||
}
|
||||
</p>
|
||||
<Button
|
||||
onClick={handleCloseModal}
|
||||
@@ -343,7 +556,9 @@ export function StakeForm() {
|
||||
{transactionStatus === 'error' && (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<XCircle className="h-16 w-16 text-destructive" />
|
||||
<h3 className="text-xl font-semibold text-center">Stake Failed</h3>
|
||||
<h3 className="text-xl font-semibold text-center">
|
||||
{mode === 'stake' ? 'Stake Failed' : 'Unstake Failed'}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground text-center break-words">
|
||||
{transactionError || 'Transaction failed'}
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user