import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { X, Lock, AlertCircle, Loader2, Clock } from 'lucide-react'; import { web3FromAddress } from '@pezkuwi/extension-dapp'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; import { Button } from '@/components/ui/button'; import { Alert, AlertDescription } from '@/components/ui/alert'; interface TokenBalance { assetId: number; symbol: string; name: string; balance: string; decimals: number; usdValue: number; isLpToken?: boolean; } interface LPStakeModalProps { isOpen: boolean; onClose: () => void; lpToken: TokenBalance | null; onStakeSuccess?: () => void; } // Pool ID mapping: LP Token assetId -> Staking Pool ID const LP_TO_POOL_ID: Record = { 0: 0, // HEZ-PEZ LP -> Pool 0 1: 1, // HEZ-USDT LP -> Pool 1 2: 2, // HEZ-DOT LP -> Pool 2 }; interface DurationOption { label: string; months: number; multiplier: number; // Reward multiplier (for display) } const DURATION_OPTIONS: DurationOption[] = [ { label: 'lpStake.month1', months: 1, multiplier: 1 }, { label: 'lpStake.month3', months: 3, multiplier: 1.5 }, { label: 'lpStake.month6', months: 6, multiplier: 2 }, { label: 'lpStake.year1', months: 12, multiplier: 3 }, ]; export const LPStakeModal: React.FC = ({ isOpen, onClose, lpToken, onStakeSuccess, }) => { const { t } = useTranslation(); const { assetHubApi, selectedAccount, isAssetHubReady } = usePezkuwi(); const [isProcessing, setIsProcessing] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [stakeAmount, setStakeAmount] = useState(''); const [selectedDuration, setSelectedDuration] = useState(1); // months if (!isOpen || !lpToken) return null; const poolId = LP_TO_POOL_ID[lpToken.assetId]; const maxBalance = parseFloat(lpToken.balance); const handleStake = async () => { if (!assetHubApi || !isAssetHubReady || !selectedAccount || poolId === undefined) { setError(t('lpStake.apiNotReady')); return; } const amount = parseFloat(stakeAmount); if (isNaN(amount) || amount <= 0) { setError(t('lpStake.invalidAmount')); return; } if (amount > maxBalance) { setError(t('lpStake.insufficientBalance')); return; } setIsProcessing(true); setError(null); setSuccess(null); try { const amountBN = BigInt(Math.floor(amount * 1e12)); const injector = await web3FromAddress(selectedAccount.address); const tx = assetHubApi.tx.assetRewards.stake(poolId, amountBN.toString()); await new Promise((resolve, reject) => { tx.signAndSend( selectedAccount.address, { signer: injector.signer }, ({ status, dispatchError }) => { if (status.isFinalized) { if (dispatchError) { if (dispatchError.isModule) { const decoded = assetHubApi.registry.findMetaError(dispatchError.asModule); reject(new Error(`${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`)); } else { reject(new Error(dispatchError.toString())); } } else { resolve(); } } } ); }); const durationOption = DURATION_OPTIONS.find(d => d.months === selectedDuration); const durationLabel = durationOption ? t(durationOption.label) : `${selectedDuration}`; setSuccess(t('lpStake.success', { amount: stakeAmount, symbol: lpToken.symbol, duration: durationLabel })); setStakeAmount(''); if (onStakeSuccess) { onStakeSuccess(); } // Close modal after success setTimeout(() => { onClose(); }, 2000); } catch (err) { setError(err instanceof Error ? err.message : t('lpStake.failed')); } finally { setIsProcessing(false); } }; const setMaxAmount = () => { setStakeAmount(lpToken.balance); }; const selectedDurationOption = DURATION_OPTIONS.find(d => d.months === selectedDuration); return (

{t('lpStake.title')}

{lpToken.symbol}

{error && ( {error} )} {success && ( {success} )}
{/* Duration Selection */}
{DURATION_OPTIONS.map((option) => ( ))}
{/* Balance Info */}
{t('lpStake.currentBalance')} {lpToken.balance} {lpToken.symbol}
{selectedDurationOption && (
{t('lpStake.rewardMultiplier')} {selectedDurationOption.multiplier}x
)}
{/* Amount Input */}
setStakeAmount(e.target.value)} placeholder="0.0" className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-3 text-white pr-20" disabled={isProcessing} max={maxBalance} min={0} step="0.0001" />
{t('lpStake.poolId', { id: poolId })}
{/* Warning */}
{t('lpStake.lockWarning')}
{/* Stake Button */}
); };